Fix crash because XSetInputFocus fail.
[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 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
32
33 #include "GHOST_SystemX11.h"
34 #include "GHOST_WindowX11.h"
35 #include "GHOST_WindowManager.h"
36 #include "GHOST_TimerManager.h"
37 #include "GHOST_EventCursor.h"
38 #include "GHOST_EventKey.h"
39 #include "GHOST_EventButton.h"
40 #include "GHOST_EventWheel.h"
41 #include "GHOST_EventNDOF.h"
42 #include "GHOST_NDOFManager.h"
43 #include "GHOST_DisplayManagerX11.h"
44
45 #include "GHOST_Debug.h"
46
47 #include <X11/Xatom.h>
48 #include <X11/keysym.h>
49 #include <X11/XKBlib.h> /* allow detectable autorepeate */
50
51 #ifdef __sgi
52
53 #if defined(_SGI_EXTRA_PREDEFINES) && !defined(NO_FAST_ATOMS)
54 #include <X11/SGIFastAtom.h>
55 #else
56 #define XSGIFastInternAtom(dpy,string,fast_name,how) XInternAtom(dpy,string,how)
57 #endif
58
59 #endif
60
61 // For timing
62
63 #include <sys/time.h>
64 #include <unistd.h>
65
66 #include <vector>
67 #include <stdio.h> // for fprintf only
68
69 typedef struct NDOFPlatformInfo {
70         Display *display;
71         Window window;
72         volatile GHOST_TEventNDOFData *currValues;
73         Atom cmdAtom;
74         Atom motionAtom;
75         Atom btnPressAtom;
76         Atom btnRelAtom;
77 } NDOFPlatformInfo;
78
79 static NDOFPlatformInfo sNdofInfo = {NULL, 0, NULL, 0, 0, 0, 0};
80
81
82 //these are for copy and select copy
83 static char *txt_cut_buffer= NULL;
84 static char *txt_select_buffer= NULL;
85
86 using namespace std;
87
88 GHOST_SystemX11::
89 GHOST_SystemX11(
90 ) : 
91         GHOST_System(),
92         m_start_time(0)
93 {
94         m_display = XOpenDisplay(NULL);
95         
96         if (!m_display) return;
97         
98 #ifdef __sgi
99         m_delete_window_atom 
100           = XSGIFastInternAtom(m_display,
101                                "WM_DELETE_WINDOW", 
102                                SGI_XA_WM_DELETE_WINDOW, False);
103 #else
104         m_delete_window_atom 
105           = XInternAtom(m_display, "WM_DELETE_WINDOW", True);
106 #endif
107
108         m_wm_protocols= XInternAtom(m_display, "WM_PROTOCOLS", False);
109         m_wm_take_focus= XInternAtom(m_display, "WM_TAKE_FOCUS", False);
110
111         // compute the initial time
112         timeval tv;
113         if (gettimeofday(&tv,NULL) == -1) {
114                 GHOST_ASSERT(false,"Could not instantiate timer!");
115         }
116
117         m_start_time = GHOST_TUns64(tv.tv_sec*1000 + tv.tv_usec/1000);
118         
119         
120         /* use detectable autorepeate, mac and windows also do this */
121         int use_xkb;
122         int xkb_opcode, xkb_event, xkb_error;
123         int xkb_major = XkbMajorVersion, xkb_minor = XkbMinorVersion;
124         
125         use_xkb = XkbQueryExtension(m_display, &xkb_opcode, &xkb_event, &xkb_error, &xkb_major, &xkb_minor);
126         if (use_xkb) {
127                 XkbSetDetectableAutoRepeat(m_display, true, NULL);
128         }
129         
130 }
131
132         GHOST_TSuccess 
133 GHOST_SystemX11::
134 init(
135 ){
136         GHOST_TSuccess success = GHOST_System::init();
137
138         if (success) {
139                 m_keyboard_vector = new char[32];
140
141                 m_displayManager = new GHOST_DisplayManagerX11(this);
142
143                 if (m_keyboard_vector && m_displayManager) {
144                         return GHOST_kSuccess;
145                 }
146         }
147
148         return GHOST_kFailure;
149 }
150
151         GHOST_TUns64
152 GHOST_SystemX11::
153 getMilliSeconds(
154 ) const {
155         timeval tv;
156         if (gettimeofday(&tv,NULL) == -1) {
157                 GHOST_ASSERT(false,"Could not compute time!");
158         }
159
160         return  GHOST_TUns64(tv.tv_sec*1000 + tv.tv_usec/1000) - m_start_time;
161 }
162         
163         GHOST_TUns8 
164 GHOST_SystemX11::
165 getNumDisplays(
166 ) const {
167         return GHOST_TUns8(1);
168 }
169
170         /**
171          * Returns the dimensions of the main display on this system.
172          * @return The dimension of the main display.
173          */
174         void 
175 GHOST_SystemX11::
176 getMainDisplayDimensions(
177         GHOST_TUns32& width,
178         GHOST_TUns32& height
179 ) const {       
180         if (m_display) {
181                 width  = DisplayWidth(m_display, DefaultScreen(m_display));
182                 height = DisplayHeight(m_display, DefaultScreen(m_display));
183         }
184 }
185
186         /**
187          * Create a new window.
188          * The new window is added to the list of windows managed.
189          * Never explicitly delete the window, use disposeWindow() instead.
190          * @param       title   The name of the window (displayed in the title bar of the window if the OS supports it).
191          * @param       left    The coordinate of the left edge of the window.
192          * @param       top             The coordinate of the top edge of the window.
193          * @param       width   The width the window.
194          * @param       height  The height the window.
195          * @param       state   The state of the window when opened.
196          * @param       type    The type of drawing context installed in this window.
197          * @param       parentWindow    Parent (embedder) window
198          * @return      The new window (or 0 if creation failed).
199          */
200         GHOST_IWindow* 
201 GHOST_SystemX11::
202 createWindow(
203         const STR_String& title,
204         GHOST_TInt32 left,
205         GHOST_TInt32 top,
206         GHOST_TUns32 width,
207         GHOST_TUns32 height,
208         GHOST_TWindowState state,
209         GHOST_TDrawingContextType type,
210         bool stereoVisual,
211         const GHOST_TEmbedderWindowID parentWindow
212 ){
213         GHOST_WindowX11 * window = 0;
214         
215         if (!m_display) return 0;
216         
217
218         
219
220         window = new GHOST_WindowX11 (
221                 this,m_display,title, left, top, width, height, state, parentWindow, 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         GHOST_WindowX11 * 
246 GHOST_SystemX11::
247 findGhostWindow(
248         Window xwind
249 ) const {
250         
251         if (xwind == 0) return NULL;
252
253         // It is not entirely safe to do this as the backptr may point
254         // to a window that has recently been removed. 
255         // We should always check the window manager's list of windows 
256         // and only process events on these windows.
257
258         vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();
259
260         vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
261         vector<GHOST_IWindow *>::const_iterator win_end = win_vec.end();
262         
263         for (; win_it != win_end; ++win_it) {
264                 GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
265                 if (window->getXWindow() == xwind) {
266                         return window;
267                 }
268         }
269         return NULL;
270         
271 }
272
273 static void SleepTillEvent(Display *display, GHOST_TInt64 maxSleep) {
274         int fd = ConnectionNumber(display);
275         fd_set fds;
276         
277         FD_ZERO(&fds);
278         FD_SET(fd, &fds);
279
280         if (maxSleep == -1) {
281             select(fd + 1, &fds, NULL, NULL, NULL);
282         } else {
283                 timeval tv;
284
285                 tv.tv_sec = maxSleep/1000;
286                 tv.tv_usec = (maxSleep - tv.tv_sec*1000)*1000;
287         
288             select(fd + 1, &fds, NULL, NULL, &tv);
289         }
290 }
291
292         bool 
293 GHOST_SystemX11::
294 processEvents(
295         bool waitForEvent
296 ){
297         // Get all the current events -- translate them into 
298         // ghost events and call base class pushEvent() method.
299         
300         bool anyProcessed = false;
301         
302         do {
303                 GHOST_TimerManager* timerMgr = getTimerManager();
304                 
305                 if (waitForEvent && m_dirty_windows.empty() && !XPending(m_display)) {
306                         GHOST_TUns64 next = timerMgr->nextFireTime();
307                         
308                         if (next==GHOST_kFireTimeNever) {
309                                 SleepTillEvent(m_display, -1);
310                         } else {
311                                 SleepTillEvent(m_display, next - getMilliSeconds());
312                         }
313                 }
314                 
315                 if (timerMgr->fireTimers(getMilliSeconds())) {
316                         anyProcessed = true;
317                 }
318                 
319                 while (XPending(m_display)) {
320                         XEvent xevent;
321                         XNextEvent(m_display, &xevent);
322                         processEvent(&xevent);
323                         anyProcessed = true;
324                 }
325                 
326                 if (generateWindowExposeEvents()) {
327                         anyProcessed = true;
328                 }
329         } while (waitForEvent && !anyProcessed);
330         
331         return anyProcessed;
332 }
333
334         void
335 GHOST_SystemX11::processEvent(XEvent *xe)
336 {
337         GHOST_WindowX11 * window = findGhostWindow(xe->xany.window);    
338         GHOST_Event * g_event = NULL;
339
340         if (!window) {
341                 return;
342         }
343         
344         switch (xe->type) {
345                 case Expose:
346                 {
347                         XExposeEvent & xee = xe->xexpose;
348
349                         if (xee.count == 0) {
350                                 // Only generate a single expose event
351                                 // per read of the event queue.
352
353                                 g_event = new 
354                                 GHOST_Event(
355                                         getMilliSeconds(),
356                                         GHOST_kEventWindowUpdate,
357                                         window
358                                 );                      
359                         }
360                         break;
361                 }
362
363                 case MotionNotify:
364                 {
365                         XMotionEvent &xme = xe->xmotion;
366                         
367                         g_event = new 
368                         GHOST_EventCursor(
369                                 getMilliSeconds(),
370                                 GHOST_kEventCursorMove,
371                                 window,
372                                 xme.x_root,
373                                 xme.y_root
374                         );
375                         break;
376                 }
377
378                 case KeyPress:
379                 case KeyRelease:
380                 {
381                         XKeyEvent *xke = &(xe->xkey);
382                 
383                         KeySym key_sym = XLookupKeysym(xke,0);
384                         char ascii;
385                         
386                         GHOST_TKey gkey = convertXKey(key_sym);
387                         GHOST_TEventType type = (xke->type == KeyPress) ? 
388                                 GHOST_kEventKeyDown : GHOST_kEventKeyUp;
389                         
390                         if (!XLookupString(xke, &ascii, 1, NULL, NULL)) {
391                                 ascii = '\0';
392                         }
393                         
394                         g_event = new
395                         GHOST_EventKey(
396                                 getMilliSeconds(),
397                                 type,
398                                 window,
399                                 gkey,
400                                 ascii
401                         );
402                         
403                 break;
404                 }
405
406                 case ButtonPress:
407                 {
408                         /* process wheel mouse events and break */
409                         if (xe->xbutton.button == 4) {
410                                 g_event = new GHOST_EventWheel(getMilliSeconds(), window, 1);
411                                 break;
412                         }
413                         if (xe->xbutton.button == 5) {
414                                 g_event = new GHOST_EventWheel(getMilliSeconds(), window, -1);
415                                 break;
416                         }
417                 }
418                 case ButtonRelease:
419                 {
420
421                         XButtonEvent & xbe = xe->xbutton;
422                         GHOST_TButtonMask gbmask = GHOST_kButtonMaskLeft;
423
424                         switch (xbe.button) {
425                                 case Button1 : gbmask = GHOST_kButtonMaskLeft; break;
426                                 case Button3 : gbmask = GHOST_kButtonMaskRight; break;
427                                 default:
428                                 case Button2 : gbmask = GHOST_kButtonMaskMiddle; break;
429                         }
430                         
431                         GHOST_TEventType type = (xbe.type == ButtonPress) ? 
432                                 GHOST_kEventButtonDown : GHOST_kEventButtonUp;
433                         
434                         g_event = new
435                         GHOST_EventButton(
436                                 getMilliSeconds(),
437                                 type,
438                                 window,
439                                 gbmask
440                         );
441                         break;
442                 }
443                         
444                         // change of size, border, layer etc.
445                 case ConfigureNotify:
446                 {
447                         /* XConfigureEvent & xce = xe->xconfigure; */
448
449                         g_event = new 
450                         GHOST_Event(
451                                 getMilliSeconds(),
452                                 GHOST_kEventWindowSize,
453                                 window
454                         );                      
455                         break;
456                 }
457
458                 case FocusIn:
459                 case FocusOut:
460                 {
461                         XFocusChangeEvent &xfe = xe->xfocus;
462                 
463                         // May have to look at the type of event and filter some
464                         // out.
465                                                                         
466                         GHOST_TEventType gtype = (xfe.type == FocusIn) ? 
467                                 GHOST_kEventWindowActivate : GHOST_kEventWindowDeactivate;
468
469                         g_event = new 
470                         GHOST_Event(    
471                                 getMilliSeconds(),
472                                 gtype,
473                                 window
474                         );
475                         break;
476
477                 }
478                 case ClientMessage:
479                 {
480                         XClientMessageEvent & xcme = xe->xclient;
481
482 #ifndef __sgi                   
483                         if (((Atom)xcme.data.l[0]) == m_delete_window_atom) {
484                                 g_event = new 
485                                 GHOST_Event(    
486                                         getMilliSeconds(),
487                                         GHOST_kEventWindowClose,
488                                         window
489                                 );
490                         } else 
491 #endif
492                         if (sNdofInfo.currValues) {
493                                 static GHOST_TEventNDOFData data = {0,0,0,0,0,0,0,0,0,0,0};
494                                 if (xcme.message_type == sNdofInfo.motionAtom)
495                                 {
496                                         data.changed = 1;
497                                         data.delta = xcme.data.s[8] - data.time;
498                                         data.time = xcme.data.s[8];
499                                         data.tx = xcme.data.s[2] >> 2;
500                                         data.ty = xcme.data.s[3] >> 2;
501                                         data.tz = xcme.data.s[4] >> 2;
502                                         data.rx = xcme.data.s[5];
503                                         data.ry = xcme.data.s[6];
504                                         data.rz =-xcme.data.s[7];
505                                         g_event = new GHOST_EventNDOF(getMilliSeconds(),
506                                                                       GHOST_kEventNDOFMotion,
507                                                                       window, data);
508                                 } else if (xcme.message_type == sNdofInfo.btnPressAtom) {
509                                         data.changed = 2;
510                                         data.delta = xcme.data.s[8] - data.time;
511                                         data.time = xcme.data.s[8];
512                                         data.buttons = xcme.data.s[2];
513                                         g_event = new GHOST_EventNDOF(getMilliSeconds(),
514                                                                       GHOST_kEventNDOFButton,
515                                                                       window, data);
516                                 }
517                         } else if (((Atom)xcme.data.l[0]) == m_wm_take_focus) {
518                                 XWindowAttributes attr;
519                                 Window fwin;
520                                 int revert_to;
521
522                                 /* as ICCCM say, we need reply this event
523                                  * with a SetInputFocus, the data[1] have
524                                  * the valid timestamp (send by the wm).
525                                  *
526                                  * Some WM send this event before the
527                                  * window is really mapped (for example
528                                  * change from virtual desktop), so we need
529                                  * to be sure that our windows is mapped
530                                  * or this call fail and close blender.
531                                  */
532                                 if (XGetWindowAttributes(m_display, xcme.window, &attr) == True) {
533                                         if (XGetInputFocus(m_display, &fwin, &revert_to) == True) {
534                                                 if (attr.map_state == IsViewable) {
535                                                         if (fwin != xcme.window)
536                                                                 XSetInputFocus(m_display, xcme.window, RevertToParent, xcme.data.l[1]);
537                                                 }
538                                         }
539                                 }
540                         } else {
541                                 /* Unknown client message, ignore */
542                         }
543                         break;
544                 }
545                 
546                 case DestroyNotify:
547                         ::exit(-1);     
548                 // We're not interested in the following things.(yet...)
549                 case NoExpose : 
550                 case GraphicsExpose :
551                 
552                 case EnterNotify:
553                 case LeaveNotify:
554                         // XCrossingEvents pointer leave enter window.
555                         break;
556                 case MapNotify:
557                 case UnmapNotify:
558                         break;
559                 case MappingNotify:
560                 case ReparentNotify:
561                         break;
562                 case SelectionRequest:
563                 {
564                         XEvent nxe;
565                         Atom target, string, compound_text, c_string;
566                         XSelectionRequestEvent *xse = &xe->xselectionrequest;
567                         
568                         target = XInternAtom(m_display, "TARGETS", False);
569                         string = XInternAtom(m_display, "STRING", False);
570                         compound_text = XInternAtom(m_display, "COMPOUND_TEXT", False);
571                         c_string = XInternAtom(m_display, "C_STRING", False);
572                         
573                         /* support obsolete clients */
574                         if (xse->property == None) {
575                                 xse->property = xse->target;
576                         }
577                         
578                         nxe.xselection.type = SelectionNotify;
579                         nxe.xselection.requestor = xse->requestor;
580                         nxe.xselection.property = xse->property;
581                         nxe.xselection.display = xse->display;
582                         nxe.xselection.selection = xse->selection;
583                         nxe.xselection.target = xse->target;
584                         nxe.xselection.time = xse->time;
585                         
586                         /*Check to see if the requestor is asking for String*/
587                         if(xse->target == string || xse->target == compound_text || xse->target == c_string) {
588                                 if (xse->selection == XInternAtom(m_display, "PRIMARY", False)) {
589                                         XChangeProperty(m_display, xse->requestor, xse->property, xse->target, 8, PropModeReplace, (unsigned char*)txt_select_buffer, strlen(txt_select_buffer));
590                                 } else if (xse->selection == XInternAtom(m_display, "CLIPBOARD", False)) {
591                                         XChangeProperty(m_display, xse->requestor, xse->property, xse->target, 8, PropModeReplace, (unsigned char*)txt_cut_buffer, strlen(txt_cut_buffer));
592                                 }
593                         } else if (xse->target == target) {
594                                 Atom alist[4];
595                                 alist[0] = target;
596                                 alist[1] = string;
597                                 alist[2] = compound_text;
598                                 alist[3] = c_string;
599                                 XChangeProperty(m_display, xse->requestor, xse->property, xse->target, 32, PropModeReplace, (unsigned char*)alist, 4);
600                                 XFlush(m_display);
601                         } else  {
602                                 //Change property to None because we do not support anything but STRING
603                                 nxe.xselection.property = None;
604                         }
605                         
606                         //Send the event to the client 0 0 == False, SelectionNotify
607                         XSendEvent(m_display, xse->requestor, 0, 0, &nxe);
608                         XFlush(m_display);
609                         break;
610                 }
611                 
612                 default: {
613                         if(xe->type == window->GetXTablet().MotionEvent) 
614                         {
615                                 XDeviceMotionEvent* data = (XDeviceMotionEvent*)xe;
616                                 window->GetXTablet().CommonData.Pressure= 
617                                         data->axis_data[2]/((float)window->GetXTablet().PressureLevels);
618                         
619                         /* the (short) cast and the &0xffff is bizarre and unexplained anywhere,
620                          * but I got garbage data without it. Found it in the xidump.c source --matt */
621                                 window->GetXTablet().CommonData.Xtilt= 
622                                         (short)(data->axis_data[3]&0xffff)/((float)window->GetXTablet().XtiltLevels);
623                                 window->GetXTablet().CommonData.Ytilt= 
624                                         (short)(data->axis_data[4]&0xffff)/((float)window->GetXTablet().YtiltLevels);
625                         }
626                         else if(xe->type == window->GetXTablet().ProxInEvent) 
627                         {
628                                 XProximityNotifyEvent* data = (XProximityNotifyEvent*)xe;
629                                 if(data->deviceid == window->GetXTablet().StylusID)
630                                         window->GetXTablet().CommonData.Active= 1;
631                                 else if(data->deviceid == window->GetXTablet().EraserID)
632                                         window->GetXTablet().CommonData.Active= 2;
633                         }
634                         else if(xe->type == window->GetXTablet().ProxOutEvent)
635                                 window->GetXTablet().CommonData.Active= 0;
636
637                         break;
638                 }
639         }
640
641         if (g_event) {
642                 pushEvent(g_event);
643         }
644 }
645
646         void *
647 GHOST_SystemX11::
648 prepareNdofInfo(volatile GHOST_TEventNDOFData *currentNdofValues)
649 {
650         const vector<GHOST_IWindow*>& v(m_windowManager->getWindows());
651         if (v.size() > 0)
652                 sNdofInfo.window = static_cast<GHOST_WindowX11*>(v[0])->getXWindow();
653         sNdofInfo.display = m_display;
654         sNdofInfo.currValues = currentNdofValues;
655         return (void*)&sNdofInfo;
656 }
657
658         GHOST_TSuccess 
659 GHOST_SystemX11::
660 getModifierKeys(
661         GHOST_ModifierKeys& keys
662 ) const {
663
664         // analyse the masks retuned from XQueryPointer.
665
666         memset(m_keyboard_vector,0,sizeof(m_keyboard_vector));
667
668         XQueryKeymap(m_display,m_keyboard_vector);
669
670         // now translate key symobols into keycodes and
671         // test with vector.
672
673         const KeyCode shift_l = XKeysymToKeycode(m_display,XK_Shift_L);
674         const KeyCode shift_r = XKeysymToKeycode(m_display,XK_Shift_R);
675         const KeyCode control_l = XKeysymToKeycode(m_display,XK_Control_L);
676         const KeyCode control_r = XKeysymToKeycode(m_display,XK_Control_R);
677         const KeyCode alt_l = XKeysymToKeycode(m_display,XK_Alt_L);
678         const KeyCode alt_r = XKeysymToKeycode(m_display,XK_Alt_R);
679
680         // Shift
681         if ((m_keyboard_vector[shift_l >> 3] >> (shift_l & 7)) & 1) {
682                 keys.set(GHOST_kModifierKeyLeftShift,true);
683         } else {
684                 keys.set(GHOST_kModifierKeyLeftShift,false);
685         }
686         if ((m_keyboard_vector[shift_r >> 3] >> (shift_r & 7)) & 1) {
687
688                 keys.set(GHOST_kModifierKeyRightShift,true);
689         } else {
690                 keys.set(GHOST_kModifierKeyRightShift,false);
691         }
692
693         // control (weep)
694         if ((m_keyboard_vector[control_l >> 3] >> (control_l & 7)) & 1) {
695                 keys.set(GHOST_kModifierKeyLeftControl,true);
696         } else {
697                 keys.set(GHOST_kModifierKeyLeftControl,false);
698         }
699         if ((m_keyboard_vector[control_r >> 3] >> (control_r & 7)) & 1) {
700                 keys.set(GHOST_kModifierKeyRightControl,true);
701         } else {
702                 keys.set(GHOST_kModifierKeyRightControl,false);
703         }
704
705         // Alt (yawn)
706         if ((m_keyboard_vector[alt_l >> 3] >> (alt_l & 7)) & 1) {
707                 keys.set(GHOST_kModifierKeyLeftAlt,true);
708         } else {
709                 keys.set(GHOST_kModifierKeyLeftAlt,false);
710         }       
711         if ((m_keyboard_vector[alt_r >> 3] >> (alt_r & 7)) & 1) {
712                 keys.set(GHOST_kModifierKeyRightAlt,true);
713         } else {
714                 keys.set(GHOST_kModifierKeyRightAlt,false);
715         }
716         return GHOST_kSuccess;
717 }
718
719         GHOST_TSuccess 
720 GHOST_SystemX11::
721 getButtons(
722         GHOST_Buttons& buttons
723 ) const {
724
725         Window root_return, child_return;
726         int rx,ry,wx,wy;
727         unsigned int mask_return;
728
729         if (XQueryPointer(
730                 m_display,
731                 RootWindow(m_display,DefaultScreen(m_display)),
732                 &root_return,
733                 &child_return,
734                 &rx,&ry,
735                 &wx,&wy,
736                 &mask_return
737         ) == False) {
738                 return GHOST_kFailure;
739         } else {
740
741                 if (mask_return & Button1Mask) {
742                         buttons.set(GHOST_kButtonMaskLeft,true);
743                 } else {
744                         buttons.set(GHOST_kButtonMaskLeft,false);
745                 }
746
747                 if (mask_return & Button2Mask) {
748                         buttons.set(GHOST_kButtonMaskMiddle,true);
749                 } else {
750                         buttons.set(GHOST_kButtonMaskMiddle,false);
751                 }
752
753                 if (mask_return & Button3Mask) {
754                         buttons.set(GHOST_kButtonMaskRight,true);
755                 } else {
756                         buttons.set(GHOST_kButtonMaskRight,false);
757                 }
758         }       
759
760         return GHOST_kSuccess;
761 }
762
763
764         GHOST_TSuccess 
765 GHOST_SystemX11::
766 getCursorPosition(
767         GHOST_TInt32& x,
768         GHOST_TInt32& y
769 ) const {
770
771         Window root_return, child_return;
772         int rx,ry,wx,wy;
773         unsigned int mask_return;
774
775         if (XQueryPointer(
776                 m_display,
777                 RootWindow(m_display,DefaultScreen(m_display)),
778                 &root_return,
779                 &child_return,
780                 &rx,&ry,
781                 &wx,&wy,
782                 &mask_return
783         ) == False) {
784                 return GHOST_kFailure;
785         } else {
786                 x = rx;
787                 y = ry;
788         }       
789         return GHOST_kSuccess;
790 }
791
792
793         GHOST_TSuccess 
794 GHOST_SystemX11::
795 setCursorPosition(
796         GHOST_TInt32 x,
797         GHOST_TInt32 y
798 ) const {
799
800         // This is a brute force move in screen coordinates
801         // XWarpPointer does relative moves so first determine the
802         // current pointer position.
803
804         int cx,cy;
805         if (getCursorPosition(cx,cy) == GHOST_kFailure) {
806                 return GHOST_kFailure;
807         }
808
809         int relx = x-cx;
810         int rely = y-cy;
811
812         XWarpPointer(m_display,None,None,0,0,0,0,relx,rely);
813         XFlush(m_display);
814         
815         return GHOST_kSuccess;
816 }
817
818
819         void
820 GHOST_SystemX11::
821 addDirtyWindow(
822         GHOST_WindowX11 * bad_wind
823 ){
824
825         GHOST_ASSERT((bad_wind != NULL), "addDirtyWindow() NULL ptr trapped (window)");
826         
827         m_dirty_windows.push_back(bad_wind);
828 }
829
830
831         bool
832 GHOST_SystemX11::
833 generateWindowExposeEvents(
834 ){
835
836         vector<GHOST_WindowX11 *>::iterator w_start = m_dirty_windows.begin();
837         vector<GHOST_WindowX11 *>::const_iterator w_end = m_dirty_windows.end();
838         bool anyProcessed = false;
839         
840         for (;w_start != w_end; ++w_start) {
841                 GHOST_Event * g_event = new 
842                         GHOST_Event(
843                                 getMilliSeconds(),
844                                 GHOST_kEventWindowUpdate,
845                                 *w_start
846                         );                      
847
848                 (*w_start)->validate(); 
849                 
850                 if (g_event) {
851                         pushEvent(g_event);
852                         anyProcessed = true;
853                 }
854         }
855
856         m_dirty_windows.clear();
857         return anyProcessed;
858 }
859
860 #define GXMAP(k,x,y) case x: k = y; break; 
861
862         GHOST_TKey
863 GHOST_SystemX11::
864 convertXKey(
865         KeySym key
866 ){
867         GHOST_TKey type;
868
869         if ((key >= XK_A) && (key <= XK_Z)) {
870                 type = GHOST_TKey( key - XK_A + int(GHOST_kKeyA));
871         } else if ((key >= XK_a) && (key <= XK_z)) {
872                 type = GHOST_TKey(key - XK_a + int(GHOST_kKeyA));
873         } else if ((key >= XK_0) && (key <= XK_9)) {
874                 type = GHOST_TKey(key - XK_0 + int(GHOST_kKey0));
875         } else if ((key >= XK_F1) && (key <= XK_F24)) {
876                 type = GHOST_TKey(key - XK_F1 + int(GHOST_kKeyF1));
877 #if defined(__sun) || defined(__sun__) 
878                 /* This is a bit of a hack, but it looks like sun
879                    Used F11 and friends for its special keys Stop,again etc..
880                    So this little patch enables F11 and F12 to work as expected
881                    following link has documentation on it: 
882                    http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4734408
883                    also from /usr/include/X11/Sunkeysym.h 
884 #define SunXK_F36               0x1005FF10      // Labeled F11
885 #define SunXK_F37               0x1005FF11      // Labeled F12 
886
887                                 mein@cs.umn.edu
888                  */
889                 
890         } else if (key == 268828432) {
891                 type = GHOST_kKeyF11;
892         } else if (key == 268828433) {
893                 type = GHOST_kKeyF12;
894 #endif
895         } else {
896                 switch(key) {
897                         GXMAP(type,XK_BackSpace,        GHOST_kKeyBackSpace);
898                         GXMAP(type,XK_Tab,              GHOST_kKeyTab);
899                         GXMAP(type,XK_Return,           GHOST_kKeyEnter);
900                         GXMAP(type,XK_Escape,           GHOST_kKeyEsc);
901                         GXMAP(type,XK_space,            GHOST_kKeySpace);
902                         
903                         GXMAP(type,XK_Linefeed,         GHOST_kKeyLinefeed);
904                         GXMAP(type,XK_semicolon,        GHOST_kKeySemicolon);
905                         GXMAP(type,XK_period,           GHOST_kKeyPeriod);
906                         GXMAP(type,XK_comma,            GHOST_kKeyComma);
907                         GXMAP(type,XK_quoteright,       GHOST_kKeyQuote);
908                         GXMAP(type,XK_quoteleft,        GHOST_kKeyAccentGrave);
909                         GXMAP(type,XK_minus,            GHOST_kKeyMinus);
910                         GXMAP(type,XK_slash,            GHOST_kKeySlash);
911                         GXMAP(type,XK_backslash,        GHOST_kKeyBackslash);
912                         GXMAP(type,XK_equal,            GHOST_kKeyEqual);
913                         GXMAP(type,XK_bracketleft,      GHOST_kKeyLeftBracket);
914                         GXMAP(type,XK_bracketright,     GHOST_kKeyRightBracket);
915                         GXMAP(type,XK_Pause,            GHOST_kKeyPause);
916                         
917                         GXMAP(type,XK_Shift_L,          GHOST_kKeyLeftShift);
918                         GXMAP(type,XK_Shift_R,          GHOST_kKeyRightShift);
919                         GXMAP(type,XK_Control_L,        GHOST_kKeyLeftControl);
920                         GXMAP(type,XK_Control_R,        GHOST_kKeyRightControl);
921                         GXMAP(type,XK_Alt_L,            GHOST_kKeyLeftAlt);
922                         GXMAP(type,XK_Alt_R,            GHOST_kKeyRightAlt);
923
924                         GXMAP(type,XK_Insert,           GHOST_kKeyInsert);
925                         GXMAP(type,XK_Delete,           GHOST_kKeyDelete);
926                         GXMAP(type,XK_Home,                     GHOST_kKeyHome);
927                         GXMAP(type,XK_End,                      GHOST_kKeyEnd);
928                         GXMAP(type,XK_Page_Up,          GHOST_kKeyUpPage);
929                         GXMAP(type,XK_Page_Down,        GHOST_kKeyDownPage);
930
931                         GXMAP(type,XK_Left,                     GHOST_kKeyLeftArrow);
932                         GXMAP(type,XK_Right,            GHOST_kKeyRightArrow);
933                         GXMAP(type,XK_Up,                       GHOST_kKeyUpArrow);
934                         GXMAP(type,XK_Down,                     GHOST_kKeyDownArrow);
935
936                         GXMAP(type,XK_Caps_Lock,        GHOST_kKeyCapsLock);
937                         GXMAP(type,XK_Scroll_Lock,      GHOST_kKeyScrollLock);
938                         GXMAP(type,XK_Num_Lock,         GHOST_kKeyNumLock);
939                         
940                                 /* keypad events */
941                                 
942                         GXMAP(type,XK_KP_0,                     GHOST_kKeyNumpad0);
943                         GXMAP(type,XK_KP_1,                     GHOST_kKeyNumpad1);
944                         GXMAP(type,XK_KP_2,                     GHOST_kKeyNumpad2);
945                         GXMAP(type,XK_KP_3,                     GHOST_kKeyNumpad3);
946                         GXMAP(type,XK_KP_4,                     GHOST_kKeyNumpad4);
947                         GXMAP(type,XK_KP_5,                     GHOST_kKeyNumpad5);
948                         GXMAP(type,XK_KP_6,                     GHOST_kKeyNumpad6);
949                         GXMAP(type,XK_KP_7,                     GHOST_kKeyNumpad7);
950                         GXMAP(type,XK_KP_8,                     GHOST_kKeyNumpad8);
951                         GXMAP(type,XK_KP_9,                     GHOST_kKeyNumpad9);
952                         GXMAP(type,XK_KP_Decimal,       GHOST_kKeyNumpadPeriod);
953
954                         GXMAP(type,XK_KP_Insert,        GHOST_kKeyNumpad0);
955                         GXMAP(type,XK_KP_End,           GHOST_kKeyNumpad1);
956                         GXMAP(type,XK_KP_Down,          GHOST_kKeyNumpad2);
957                         GXMAP(type,XK_KP_Page_Down,     GHOST_kKeyNumpad3);
958                         GXMAP(type,XK_KP_Left,          GHOST_kKeyNumpad4);
959                         GXMAP(type,XK_KP_Begin,         GHOST_kKeyNumpad5);
960                         GXMAP(type,XK_KP_Right,         GHOST_kKeyNumpad6);
961                         GXMAP(type,XK_KP_Home,          GHOST_kKeyNumpad7);
962                         GXMAP(type,XK_KP_Up,            GHOST_kKeyNumpad8);
963                         GXMAP(type,XK_KP_Page_Up,       GHOST_kKeyNumpad9);
964                         GXMAP(type,XK_KP_Delete,        GHOST_kKeyNumpadPeriod);
965
966                         GXMAP(type,XK_KP_Enter,         GHOST_kKeyNumpadEnter);
967                         GXMAP(type,XK_KP_Add,           GHOST_kKeyNumpadPlus);
968                         GXMAP(type,XK_KP_Subtract,      GHOST_kKeyNumpadMinus);
969                         GXMAP(type,XK_KP_Multiply,      GHOST_kKeyNumpadAsterisk);
970                         GXMAP(type,XK_KP_Divide,        GHOST_kKeyNumpadSlash);
971
972                                 /* some extra sun cruft (NICE KEYBOARD!) */
973 #ifdef __sun__
974                         GXMAP(type,0xffde,                      GHOST_kKeyNumpad1);
975                         GXMAP(type,0xffe0,                      GHOST_kKeyNumpad3);
976                         GXMAP(type,0xffdc,                      GHOST_kKeyNumpad5);
977                         GXMAP(type,0xffd8,                      GHOST_kKeyNumpad7);
978                         GXMAP(type,0xffda,                      GHOST_kKeyNumpad9);
979
980                         GXMAP(type,0xffd6,                      GHOST_kKeyNumpadSlash);
981                         GXMAP(type,0xffd7,                      GHOST_kKeyNumpadAsterisk);
982 #endif
983
984                         default :
985                                 type = GHOST_kKeyUnknown;
986                                 break;
987                 }
988         }
989
990         return type;
991 }
992
993 #undef GXMAP
994
995         GHOST_TUns8*
996 GHOST_SystemX11::
997 getClipboard(int flag
998 ) const {
999         //Flag 
1000         //0 = Regular clipboard 1 = selection
1001         static Atom Primary_atom, clip_String, compound_text, a_text, a_string;
1002         Atom rtype;
1003         Window m_window, owner;
1004         unsigned char *data, *tmp_data;
1005         int bits, count;
1006         unsigned long len, bytes;
1007         XEvent xevent;
1008         
1009         vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();
1010         vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
1011         GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
1012         m_window = window->getXWindow();
1013
1014         clip_String = XInternAtom(m_display, "_BLENDER_STRING", False);
1015         compound_text = XInternAtom(m_display, "COMPOUND_TEXT", False);
1016         a_text= XInternAtom(m_display, "TEXT", False);
1017         a_string= XInternAtom(m_display, "STRING", False);
1018
1019         //lets check the owner and if it is us then return the static buffer
1020         if(flag == 0) {
1021                 Primary_atom = XInternAtom(m_display, "CLIPBOARD", False);
1022                 owner = XGetSelectionOwner(m_display, Primary_atom);
1023                 if (owner == m_window) {
1024                         data = (unsigned char*) malloc(strlen(txt_cut_buffer)+1);
1025                         strcpy((char*)data, txt_cut_buffer);
1026                         return (GHOST_TUns8*)data;
1027                 } else if (owner == None) {
1028                         return NULL;
1029                 }
1030         } else {
1031                 Primary_atom = XInternAtom(m_display, "PRIMARY", False);
1032                 owner = XGetSelectionOwner(m_display, Primary_atom);
1033                 if (owner == m_window) {
1034                         data = (unsigned char*) malloc(strlen(txt_select_buffer)+1);
1035                         strcpy((char*)data, txt_select_buffer);
1036                         return (GHOST_TUns8*)data;
1037                 } else if (owner == None) {
1038                         return NULL;
1039                 }
1040         }
1041
1042         if(!Primary_atom) {
1043                 return NULL;
1044         }
1045         
1046         XDeleteProperty(m_display, m_window, Primary_atom);
1047         XConvertSelection(m_display, Primary_atom, compound_text, clip_String, m_window, CurrentTime); //XA_STRING
1048         XFlush(m_display);
1049
1050         //This needs to change so we do not wait for ever or check owner first
1051         count= 1;
1052         while(1) {
1053                 XNextEvent(m_display, &xevent);
1054                 if(xevent.type == SelectionNotify) {
1055                         if (xevent.xselection.property == None) {
1056                                 /* Ok, the client can't convert the property
1057                                  * to some that we can handle, try other types..
1058                                  */
1059                                 if (count == 1) {
1060                                         XConvertSelection(m_display, Primary_atom, a_text, clip_String, m_window, CurrentTime);
1061                                         count++;
1062                                 }
1063                                 else if (count == 2) {
1064                                         XConvertSelection(m_display, Primary_atom, a_string, clip_String, m_window, CurrentTime);
1065                                         count++;
1066                                 }
1067                                 else {
1068                                         /* Ok, the owner of the selection can't 
1069                                          * convert the data to something that we can
1070                                          * handle.
1071                                          */
1072                                         return(NULL);
1073                                 }
1074                         }
1075                         else {
1076                                 if(XGetWindowProperty(m_display, m_window, xevent.xselection.property , 0L, 4096L, False, AnyPropertyType, &rtype, &bits, &len, &bytes, &data) == Success) {
1077                                         if (data) {
1078                                                 if (bits == 8 && (rtype == compound_text || rtype == a_text || rtype == a_string)) {
1079                                                         tmp_data = (unsigned char*) malloc(strlen((char*)data)+1);
1080                                                         strcpy((char*)tmp_data, (char*)data);
1081                                                 }
1082                                                 else
1083                                                         tmp_data= NULL;
1084
1085                                                 XFree(data);
1086                                                 return (GHOST_TUns8*)tmp_data;
1087                                         }
1088                                 }
1089                                 return(NULL);
1090                         }
1091                 }
1092         }
1093 }
1094
1095         void
1096 GHOST_SystemX11::
1097 putClipboard(
1098 GHOST_TInt8 *buffer, int flag) const
1099 {
1100         static Atom Primary_atom;
1101         Window m_window, owner;
1102         
1103         if(!buffer) {return;}
1104         
1105         if(flag == 0) {
1106                 Primary_atom = XInternAtom(m_display, "CLIPBOARD", False);
1107                 if(txt_cut_buffer) { free((void*)txt_cut_buffer); }
1108                 
1109                 txt_cut_buffer = (char*) malloc(strlen(buffer)+1);
1110                 strcpy(txt_cut_buffer, buffer);
1111         } else {
1112                 Primary_atom = XInternAtom(m_display, "PRIMARY", False);
1113                 if(txt_select_buffer) { free((void*)txt_select_buffer); }
1114                 
1115                 txt_select_buffer = (char*) malloc(strlen(buffer)+1);
1116                 strcpy(txt_select_buffer, buffer);
1117         }
1118         
1119         vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();
1120         vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
1121         GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
1122         m_window = window->getXWindow();
1123
1124         if(!Primary_atom) {
1125                 return;
1126         }
1127         
1128         XSetSelectionOwner(m_display, Primary_atom, m_window, CurrentTime);
1129         owner = XGetSelectionOwner(m_display, Primary_atom);
1130         if (owner != m_window)
1131                 fprintf(stderr, "failed to own primary\n");
1132         
1133         return;
1134 }
1135