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