[#17850] Copying text from Eric4 to Blender crashes Blender
[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                                 /* as ICCCM say, we need reply this event
519                                  * with a SetInputFocus, the data[1] have
520                                  * the valid timestamp (send by the wm).
521                                  */
522                                 XSetInputFocus(m_display, xcme.window, RevertToParent, xcme.data.l[1]);
523                         } else {
524                                 /* Unknown client message, ignore */
525                         }
526                         break;
527                 }
528                 
529                 case DestroyNotify:
530                         ::exit(-1);     
531                 // We're not interested in the following things.(yet...)
532                 case NoExpose : 
533                 case GraphicsExpose :
534                 
535                 case EnterNotify:
536                 case LeaveNotify:
537                         // XCrossingEvents pointer leave enter window.
538                         break;
539                 case MapNotify:
540                 case UnmapNotify:
541                         break;
542                 case MappingNotify:
543                 case ReparentNotify:
544                         break;
545                 case SelectionRequest:
546                 {
547                         XEvent nxe;
548                         Atom target, string, compound_text, c_string;
549                         XSelectionRequestEvent *xse = &xe->xselectionrequest;
550                         
551                         target = XInternAtom(m_display, "TARGETS", False);
552                         string = XInternAtom(m_display, "STRING", False);
553                         compound_text = XInternAtom(m_display, "COMPOUND_TEXT", False);
554                         c_string = XInternAtom(m_display, "C_STRING", False);
555                         
556                         /* support obsolete clients */
557                         if (xse->property == None) {
558                                 xse->property = xse->target;
559                         }
560                         
561                         nxe.xselection.type = SelectionNotify;
562                         nxe.xselection.requestor = xse->requestor;
563                         nxe.xselection.property = xse->property;
564                         nxe.xselection.display = xse->display;
565                         nxe.xselection.selection = xse->selection;
566                         nxe.xselection.target = xse->target;
567                         nxe.xselection.time = xse->time;
568                         
569                         /*Check to see if the requestor is asking for String*/
570                         if(xse->target == string || xse->target == compound_text || xse->target == c_string) {
571                                 if (xse->selection == XInternAtom(m_display, "PRIMARY", False)) {
572                                         XChangeProperty(m_display, xse->requestor, xse->property, xse->target, 8, PropModeReplace, (unsigned char*)txt_select_buffer, strlen(txt_select_buffer));
573                                 } else if (xse->selection == XInternAtom(m_display, "CLIPBOARD", False)) {
574                                         XChangeProperty(m_display, xse->requestor, xse->property, xse->target, 8, PropModeReplace, (unsigned char*)txt_cut_buffer, strlen(txt_cut_buffer));
575                                 }
576                         } else if (xse->target == target) {
577                                 Atom alist[4];
578                                 alist[0] = target;
579                                 alist[1] = string;
580                                 alist[2] = compound_text;
581                                 alist[3] = c_string;
582                                 XChangeProperty(m_display, xse->requestor, xse->property, xse->target, 32, PropModeReplace, (unsigned char*)alist, 4);
583                                 XFlush(m_display);
584                         } else  {
585                                 //Change property to None because we do not support anything but STRING
586                                 nxe.xselection.property = None;
587                         }
588                         
589                         //Send the event to the client 0 0 == False, SelectionNotify
590                         XSendEvent(m_display, xse->requestor, 0, 0, &nxe);
591                         XFlush(m_display);
592                         break;
593                 }
594                 
595                 default: {
596                         if(xe->type == window->GetXTablet().MotionEvent) 
597                         {
598                                 XDeviceMotionEvent* data = (XDeviceMotionEvent*)xe;
599                                 window->GetXTablet().CommonData.Pressure= 
600                                         data->axis_data[2]/((float)window->GetXTablet().PressureLevels);
601                         
602                         /* the (short) cast and the &0xffff is bizarre and unexplained anywhere,
603                          * but I got garbage data without it. Found it in the xidump.c source --matt */
604                                 window->GetXTablet().CommonData.Xtilt= 
605                                         (short)(data->axis_data[3]&0xffff)/((float)window->GetXTablet().XtiltLevels);
606                                 window->GetXTablet().CommonData.Ytilt= 
607                                         (short)(data->axis_data[4]&0xffff)/((float)window->GetXTablet().YtiltLevels);
608                         }
609                         else if(xe->type == window->GetXTablet().ProxInEvent) 
610                         {
611                                 XProximityNotifyEvent* data = (XProximityNotifyEvent*)xe;
612                                 if(data->deviceid == window->GetXTablet().StylusID)
613                                         window->GetXTablet().CommonData.Active= 1;
614                                 else if(data->deviceid == window->GetXTablet().EraserID)
615                                         window->GetXTablet().CommonData.Active= 2;
616                         }
617                         else if(xe->type == window->GetXTablet().ProxOutEvent)
618                                 window->GetXTablet().CommonData.Active= 0;
619
620                         break;
621                 }
622         }
623
624         if (g_event) {
625                 pushEvent(g_event);
626         }
627 }
628
629         void *
630 GHOST_SystemX11::
631 prepareNdofInfo(volatile GHOST_TEventNDOFData *currentNdofValues)
632 {
633         const vector<GHOST_IWindow*>& v(m_windowManager->getWindows());
634         if (v.size() > 0)
635                 sNdofInfo.window = static_cast<GHOST_WindowX11*>(v[0])->getXWindow();
636         sNdofInfo.display = m_display;
637         sNdofInfo.currValues = currentNdofValues;
638         return (void*)&sNdofInfo;
639 }
640
641         GHOST_TSuccess 
642 GHOST_SystemX11::
643 getModifierKeys(
644         GHOST_ModifierKeys& keys
645 ) const {
646
647         // analyse the masks retuned from XQueryPointer.
648
649         memset(m_keyboard_vector,0,sizeof(m_keyboard_vector));
650
651         XQueryKeymap(m_display,m_keyboard_vector);
652
653         // now translate key symobols into keycodes and
654         // test with vector.
655
656         const KeyCode shift_l = XKeysymToKeycode(m_display,XK_Shift_L);
657         const KeyCode shift_r = XKeysymToKeycode(m_display,XK_Shift_R);
658         const KeyCode control_l = XKeysymToKeycode(m_display,XK_Control_L);
659         const KeyCode control_r = XKeysymToKeycode(m_display,XK_Control_R);
660         const KeyCode alt_l = XKeysymToKeycode(m_display,XK_Alt_L);
661         const KeyCode alt_r = XKeysymToKeycode(m_display,XK_Alt_R);
662
663         // Shift
664         if ((m_keyboard_vector[shift_l >> 3] >> (shift_l & 7)) & 1) {
665                 keys.set(GHOST_kModifierKeyLeftShift,true);
666         } else {
667                 keys.set(GHOST_kModifierKeyLeftShift,false);
668         }
669         if ((m_keyboard_vector[shift_r >> 3] >> (shift_r & 7)) & 1) {
670
671                 keys.set(GHOST_kModifierKeyRightShift,true);
672         } else {
673                 keys.set(GHOST_kModifierKeyRightShift,false);
674         }
675
676         // control (weep)
677         if ((m_keyboard_vector[control_l >> 3] >> (control_l & 7)) & 1) {
678                 keys.set(GHOST_kModifierKeyLeftControl,true);
679         } else {
680                 keys.set(GHOST_kModifierKeyLeftControl,false);
681         }
682         if ((m_keyboard_vector[control_r >> 3] >> (control_r & 7)) & 1) {
683                 keys.set(GHOST_kModifierKeyRightControl,true);
684         } else {
685                 keys.set(GHOST_kModifierKeyRightControl,false);
686         }
687
688         // Alt (yawn)
689         if ((m_keyboard_vector[alt_l >> 3] >> (alt_l & 7)) & 1) {
690                 keys.set(GHOST_kModifierKeyLeftAlt,true);
691         } else {
692                 keys.set(GHOST_kModifierKeyLeftAlt,false);
693         }       
694         if ((m_keyboard_vector[alt_r >> 3] >> (alt_r & 7)) & 1) {
695                 keys.set(GHOST_kModifierKeyRightAlt,true);
696         } else {
697                 keys.set(GHOST_kModifierKeyRightAlt,false);
698         }
699         return GHOST_kSuccess;
700 }
701
702         GHOST_TSuccess 
703 GHOST_SystemX11::
704 getButtons(
705         GHOST_Buttons& buttons
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
724                 if (mask_return & Button1Mask) {
725                         buttons.set(GHOST_kButtonMaskLeft,true);
726                 } else {
727                         buttons.set(GHOST_kButtonMaskLeft,false);
728                 }
729
730                 if (mask_return & Button2Mask) {
731                         buttons.set(GHOST_kButtonMaskMiddle,true);
732                 } else {
733                         buttons.set(GHOST_kButtonMaskMiddle,false);
734                 }
735
736                 if (mask_return & Button3Mask) {
737                         buttons.set(GHOST_kButtonMaskRight,true);
738                 } else {
739                         buttons.set(GHOST_kButtonMaskRight,false);
740                 }
741         }       
742
743         return GHOST_kSuccess;
744 }
745
746
747         GHOST_TSuccess 
748 GHOST_SystemX11::
749 getCursorPosition(
750         GHOST_TInt32& x,
751         GHOST_TInt32& y
752 ) const {
753
754         Window root_return, child_return;
755         int rx,ry,wx,wy;
756         unsigned int mask_return;
757
758         if (XQueryPointer(
759                 m_display,
760                 RootWindow(m_display,DefaultScreen(m_display)),
761                 &root_return,
762                 &child_return,
763                 &rx,&ry,
764                 &wx,&wy,
765                 &mask_return
766         ) == False) {
767                 return GHOST_kFailure;
768         } else {
769                 x = rx;
770                 y = ry;
771         }       
772         return GHOST_kSuccess;
773 }
774
775
776         GHOST_TSuccess 
777 GHOST_SystemX11::
778 setCursorPosition(
779         GHOST_TInt32 x,
780         GHOST_TInt32 y
781 ) const {
782
783         // This is a brute force move in screen coordinates
784         // XWarpPointer does relative moves so first determine the
785         // current pointer position.
786
787         int cx,cy;
788         if (getCursorPosition(cx,cy) == GHOST_kFailure) {
789                 return GHOST_kFailure;
790         }
791
792         int relx = x-cx;
793         int rely = y-cy;
794
795         XWarpPointer(m_display,None,None,0,0,0,0,relx,rely);
796         XFlush(m_display);
797         
798         return GHOST_kSuccess;
799 }
800
801
802         void
803 GHOST_SystemX11::
804 addDirtyWindow(
805         GHOST_WindowX11 * bad_wind
806 ){
807
808         GHOST_ASSERT((bad_wind != NULL), "addDirtyWindow() NULL ptr trapped (window)");
809         
810         m_dirty_windows.push_back(bad_wind);
811 }
812
813
814         bool
815 GHOST_SystemX11::
816 generateWindowExposeEvents(
817 ){
818
819         vector<GHOST_WindowX11 *>::iterator w_start = m_dirty_windows.begin();
820         vector<GHOST_WindowX11 *>::const_iterator w_end = m_dirty_windows.end();
821         bool anyProcessed = false;
822         
823         for (;w_start != w_end; ++w_start) {
824                 GHOST_Event * g_event = new 
825                         GHOST_Event(
826                                 getMilliSeconds(),
827                                 GHOST_kEventWindowUpdate,
828                                 *w_start
829                         );                      
830
831                 (*w_start)->validate(); 
832                 
833                 if (g_event) {
834                         pushEvent(g_event);
835                         anyProcessed = true;
836                 }
837         }
838
839         m_dirty_windows.clear();
840         return anyProcessed;
841 }
842
843 #define GXMAP(k,x,y) case x: k = y; break; 
844
845         GHOST_TKey
846 GHOST_SystemX11::
847 convertXKey(
848         KeySym key
849 ){
850         GHOST_TKey type;
851
852         if ((key >= XK_A) && (key <= XK_Z)) {
853                 type = GHOST_TKey( key - XK_A + int(GHOST_kKeyA));
854         } else if ((key >= XK_a) && (key <= XK_z)) {
855                 type = GHOST_TKey(key - XK_a + int(GHOST_kKeyA));
856         } else if ((key >= XK_0) && (key <= XK_9)) {
857                 type = GHOST_TKey(key - XK_0 + int(GHOST_kKey0));
858         } else if ((key >= XK_F1) && (key <= XK_F24)) {
859                 type = GHOST_TKey(key - XK_F1 + int(GHOST_kKeyF1));
860 #if defined(__sun) || defined(__sun__) 
861                 /* This is a bit of a hack, but it looks like sun
862                    Used F11 and friends for its special keys Stop,again etc..
863                    So this little patch enables F11 and F12 to work as expected
864                    following link has documentation on it: 
865                    http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4734408
866                    also from /usr/include/X11/Sunkeysym.h 
867 #define SunXK_F36               0x1005FF10      // Labeled F11
868 #define SunXK_F37               0x1005FF11      // Labeled F12 
869
870                                 mein@cs.umn.edu
871                  */
872                 
873         } else if (key == 268828432) {
874                 type = GHOST_kKeyF11;
875         } else if (key == 268828433) {
876                 type = GHOST_kKeyF12;
877 #endif
878         } else {
879                 switch(key) {
880                         GXMAP(type,XK_BackSpace,        GHOST_kKeyBackSpace);
881                         GXMAP(type,XK_Tab,              GHOST_kKeyTab);
882                         GXMAP(type,XK_Return,           GHOST_kKeyEnter);
883                         GXMAP(type,XK_Escape,           GHOST_kKeyEsc);
884                         GXMAP(type,XK_space,            GHOST_kKeySpace);
885                         
886                         GXMAP(type,XK_Linefeed,         GHOST_kKeyLinefeed);
887                         GXMAP(type,XK_semicolon,        GHOST_kKeySemicolon);
888                         GXMAP(type,XK_period,           GHOST_kKeyPeriod);
889                         GXMAP(type,XK_comma,            GHOST_kKeyComma);
890                         GXMAP(type,XK_quoteright,       GHOST_kKeyQuote);
891                         GXMAP(type,XK_quoteleft,        GHOST_kKeyAccentGrave);
892                         GXMAP(type,XK_minus,            GHOST_kKeyMinus);
893                         GXMAP(type,XK_slash,            GHOST_kKeySlash);
894                         GXMAP(type,XK_backslash,        GHOST_kKeyBackslash);
895                         GXMAP(type,XK_equal,            GHOST_kKeyEqual);
896                         GXMAP(type,XK_bracketleft,      GHOST_kKeyLeftBracket);
897                         GXMAP(type,XK_bracketright,     GHOST_kKeyRightBracket);
898                         GXMAP(type,XK_Pause,            GHOST_kKeyPause);
899                         
900                         GXMAP(type,XK_Shift_L,          GHOST_kKeyLeftShift);
901                         GXMAP(type,XK_Shift_R,          GHOST_kKeyRightShift);
902                         GXMAP(type,XK_Control_L,        GHOST_kKeyLeftControl);
903                         GXMAP(type,XK_Control_R,        GHOST_kKeyRightControl);
904                         GXMAP(type,XK_Alt_L,            GHOST_kKeyLeftAlt);
905                         GXMAP(type,XK_Alt_R,            GHOST_kKeyRightAlt);
906
907                         GXMAP(type,XK_Insert,           GHOST_kKeyInsert);
908                         GXMAP(type,XK_Delete,           GHOST_kKeyDelete);
909                         GXMAP(type,XK_Home,                     GHOST_kKeyHome);
910                         GXMAP(type,XK_End,                      GHOST_kKeyEnd);
911                         GXMAP(type,XK_Page_Up,          GHOST_kKeyUpPage);
912                         GXMAP(type,XK_Page_Down,        GHOST_kKeyDownPage);
913
914                         GXMAP(type,XK_Left,                     GHOST_kKeyLeftArrow);
915                         GXMAP(type,XK_Right,            GHOST_kKeyRightArrow);
916                         GXMAP(type,XK_Up,                       GHOST_kKeyUpArrow);
917                         GXMAP(type,XK_Down,                     GHOST_kKeyDownArrow);
918
919                         GXMAP(type,XK_Caps_Lock,        GHOST_kKeyCapsLock);
920                         GXMAP(type,XK_Scroll_Lock,      GHOST_kKeyScrollLock);
921                         GXMAP(type,XK_Num_Lock,         GHOST_kKeyNumLock);
922                         
923                                 /* keypad events */
924                                 
925                         GXMAP(type,XK_KP_0,                     GHOST_kKeyNumpad0);
926                         GXMAP(type,XK_KP_1,                     GHOST_kKeyNumpad1);
927                         GXMAP(type,XK_KP_2,                     GHOST_kKeyNumpad2);
928                         GXMAP(type,XK_KP_3,                     GHOST_kKeyNumpad3);
929                         GXMAP(type,XK_KP_4,                     GHOST_kKeyNumpad4);
930                         GXMAP(type,XK_KP_5,                     GHOST_kKeyNumpad5);
931                         GXMAP(type,XK_KP_6,                     GHOST_kKeyNumpad6);
932                         GXMAP(type,XK_KP_7,                     GHOST_kKeyNumpad7);
933                         GXMAP(type,XK_KP_8,                     GHOST_kKeyNumpad8);
934                         GXMAP(type,XK_KP_9,                     GHOST_kKeyNumpad9);
935                         GXMAP(type,XK_KP_Decimal,       GHOST_kKeyNumpadPeriod);
936
937                         GXMAP(type,XK_KP_Insert,        GHOST_kKeyNumpad0);
938                         GXMAP(type,XK_KP_End,           GHOST_kKeyNumpad1);
939                         GXMAP(type,XK_KP_Down,          GHOST_kKeyNumpad2);
940                         GXMAP(type,XK_KP_Page_Down,     GHOST_kKeyNumpad3);
941                         GXMAP(type,XK_KP_Left,          GHOST_kKeyNumpad4);
942                         GXMAP(type,XK_KP_Begin,         GHOST_kKeyNumpad5);
943                         GXMAP(type,XK_KP_Right,         GHOST_kKeyNumpad6);
944                         GXMAP(type,XK_KP_Home,          GHOST_kKeyNumpad7);
945                         GXMAP(type,XK_KP_Up,            GHOST_kKeyNumpad8);
946                         GXMAP(type,XK_KP_Page_Up,       GHOST_kKeyNumpad9);
947                         GXMAP(type,XK_KP_Delete,        GHOST_kKeyNumpadPeriod);
948
949                         GXMAP(type,XK_KP_Enter,         GHOST_kKeyNumpadEnter);
950                         GXMAP(type,XK_KP_Add,           GHOST_kKeyNumpadPlus);
951                         GXMAP(type,XK_KP_Subtract,      GHOST_kKeyNumpadMinus);
952                         GXMAP(type,XK_KP_Multiply,      GHOST_kKeyNumpadAsterisk);
953                         GXMAP(type,XK_KP_Divide,        GHOST_kKeyNumpadSlash);
954
955                                 /* some extra sun cruft (NICE KEYBOARD!) */
956 #ifdef __sun__
957                         GXMAP(type,0xffde,                      GHOST_kKeyNumpad1);
958                         GXMAP(type,0xffe0,                      GHOST_kKeyNumpad3);
959                         GXMAP(type,0xffdc,                      GHOST_kKeyNumpad5);
960                         GXMAP(type,0xffd8,                      GHOST_kKeyNumpad7);
961                         GXMAP(type,0xffda,                      GHOST_kKeyNumpad9);
962
963                         GXMAP(type,0xffd6,                      GHOST_kKeyNumpadSlash);
964                         GXMAP(type,0xffd7,                      GHOST_kKeyNumpadAsterisk);
965 #endif
966
967                         default :
968                                 type = GHOST_kKeyUnknown;
969                                 break;
970                 }
971         }
972
973         return type;
974 }
975
976 #undef GXMAP
977
978         GHOST_TUns8*
979 GHOST_SystemX11::
980 getClipboard(int flag
981 ) const {
982         //Flag 
983         //0 = Regular clipboard 1 = selection
984         static Atom Primary_atom, clip_String, compound_text;
985         Atom rtype;
986         Window m_window, owner;
987         unsigned char *data, *tmp_data;
988         int bits;
989         unsigned long len, bytes;
990         XEvent xevent;
991         
992         vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();
993         vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
994         GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
995         m_window = window->getXWindow();
996
997         clip_String = XInternAtom(m_display, "_BLENDER_STRING", False);
998         compound_text = XInternAtom(m_display, "COMPOUND_TEXT", False);
999
1000         //lets check the owner and if it is us then return the static buffer
1001         if(flag == 0) {
1002                 Primary_atom = XInternAtom(m_display, "CLIPBOARD", False);
1003                 owner = XGetSelectionOwner(m_display, Primary_atom);
1004                 if (owner == m_window) {
1005                         data = (unsigned char*) malloc(strlen(txt_cut_buffer)+1);
1006                         strcpy((char*)data, txt_cut_buffer);
1007                         return (GHOST_TUns8*)data;
1008                 } else if (owner == None) {
1009                         return NULL;
1010                 }
1011         } else {
1012                 Primary_atom = XInternAtom(m_display, "PRIMARY", False);
1013                 owner = XGetSelectionOwner(m_display, Primary_atom);
1014                 if (owner == m_window) {
1015                         data = (unsigned char*) malloc(strlen(txt_select_buffer)+1);
1016                         strcpy((char*)data, txt_select_buffer);
1017                         return (GHOST_TUns8*)data;
1018                 } else if (owner == None) {
1019                         return NULL;
1020                 }
1021         }
1022
1023         if(!Primary_atom) {
1024                 return NULL;
1025         }
1026         
1027         XDeleteProperty(m_display, m_window, Primary_atom);
1028         XConvertSelection(m_display, Primary_atom, compound_text, clip_String, m_window, CurrentTime); //XA_STRING
1029         XFlush(m_display);
1030
1031         //This needs to change so we do not wait for ever or check owner first
1032         while(1) {
1033                 XNextEvent(m_display, &xevent);
1034                 if(xevent.type == SelectionNotify) { 
1035                         if (xevent.xselection.property ) { /* eric4 on linux gives zero Atom xevent.xselection.property value, closes blender instantly */
1036                                 if(XGetWindowProperty(m_display, m_window, xevent.xselection.property , 0L, 4096L, False, AnyPropertyType, &rtype, &bits, &len, &bytes, &data) == Success) {
1037                                         if (data) {
1038                                                 tmp_data = (unsigned char*) malloc(strlen((char*)data)+1);
1039                                                 strcpy((char*)tmp_data, (char*)data);
1040                                                 XFree(data);
1041                                                 return (GHOST_TUns8*)tmp_data;
1042                                         }
1043                                 }
1044                         }
1045                         else {
1046                                 fprintf(stderr, "error: cut buffer had a zero xevent.xselection.property, FIXME\n"); // XXX fix this problem!
1047                         }
1048                         return NULL;
1049                 }
1050         }
1051 }
1052
1053         void
1054 GHOST_SystemX11::
1055 putClipboard(
1056 GHOST_TInt8 *buffer, int flag) const
1057 {
1058         static Atom Primary_atom;
1059         Window m_window, owner;
1060         
1061         if(!buffer) {return;}
1062         
1063         if(flag == 0) {
1064                 Primary_atom = XInternAtom(m_display, "CLIPBOARD", False);
1065                 if(txt_cut_buffer) { free((void*)txt_cut_buffer); }
1066                 
1067                 txt_cut_buffer = (char*) malloc(strlen(buffer)+1);
1068                 strcpy(txt_cut_buffer, buffer);
1069         } else {
1070                 Primary_atom = XInternAtom(m_display, "PRIMARY", False);
1071                 if(txt_select_buffer) { free((void*)txt_select_buffer); }
1072                 
1073                 txt_select_buffer = (char*) malloc(strlen(buffer)+1);
1074                 strcpy(txt_select_buffer, buffer);
1075         }
1076         
1077         vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();
1078         vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
1079         GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
1080         m_window = window->getXWindow();
1081
1082         if(!Primary_atom) {
1083                 return;
1084         }
1085         
1086         XSetSelectionOwner(m_display, Primary_atom, m_window, CurrentTime);
1087         owner = XGetSelectionOwner(m_display, Primary_atom);
1088         if (owner != m_window)
1089                 fprintf(stderr, "failed to own primary\n");
1090         
1091         return;
1092 }
1093