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