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