dc519039af64d832035bc649c7b4857060621664
[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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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  * Part of this code has been taken from Qt, under LGPL license
27  * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
28  *
29  * ***** END GPL LICENSE BLOCK *****
30  */
31
32 #include "GHOST_SystemX11.h"
33 #include "GHOST_WindowX11.h"
34 #include "GHOST_WindowManager.h"
35 #include "GHOST_TimerManager.h"
36 #include "GHOST_EventCursor.h"
37 #include "GHOST_EventKey.h"
38 #include "GHOST_EventButton.h"
39 #include "GHOST_EventWheel.h"
40 #include "GHOST_EventNDOF.h"
41 #include "GHOST_NDOFManagerX11.h"
42 #include "GHOST_DisplayManagerX11.h"
43
44 #include "GHOST_Debug.h"
45
46 #include <X11/Xatom.h>
47 #include <X11/keysym.h>
48 #include <X11/XKBlib.h> /* allow detectable autorepeat */
49
50 #ifdef __sgi
51
52 #if defined(_SGI_EXTRA_PREDEFINES) && !defined(NO_FAST_ATOMS)
53 #include <X11/SGIFastAtom.h>
54 #else
55 #define XSGIFastInternAtom(dpy,string,fast_name,how) XInternAtom(dpy,string,how)
56 #endif
57
58 #endif
59
60 // For timing
61
62 #include <sys/time.h>
63 #include <unistd.h>
64
65 #include <iostream>
66 #include <vector>
67 #include <stdio.h> // for fprintf only
68 #include <cstdlib> // for exit
69
70 #ifndef PREFIX
71 #  define PREFIX "/usr/local"
72 #endif
73
74 // [mce] these are for communication with the plugin
75 typedef struct NDOFPlatformInfo {
76         Display *display;
77         Window window;
78         volatile GHOST_TEventNDOFMotionData *currValues;
79         Atom cmdAtom;
80         Atom motionAtom;
81         Atom btnPressAtom;
82         Atom btnRelAtom;
83 } NDOFPlatformInfo;
84
85 static NDOFPlatformInfo sNdofInfo = {NULL, 0, NULL, 0, 0, 0, 0};
86
87 //these are for copy and select copy
88 static char *txt_cut_buffer= NULL;
89 static char *txt_select_buffer= NULL;
90
91 using namespace std;
92
93 GHOST_SystemX11::
94 GHOST_SystemX11(
95 ) : 
96         GHOST_System(),
97         m_start_time(0)
98 {
99         m_display = XOpenDisplay(NULL);
100         
101         if (!m_display) {
102                 std::cerr << "Unable to open a display" << std::endl;
103                 abort(); //was return before, but this would just mean it will crash later
104         }
105         
106 #ifdef __sgi
107         m_delete_window_atom 
108           = XSGIFastInternAtom(m_display,
109                                "WM_DELETE_WINDOW", 
110                                SGI_XA_WM_DELETE_WINDOW, False);
111 #else
112         m_delete_window_atom 
113           = XInternAtom(m_display, "WM_DELETE_WINDOW", True);
114 #endif
115
116         m_wm_protocols= XInternAtom(m_display, "WM_PROTOCOLS", False);
117         m_wm_take_focus= XInternAtom(m_display, "WM_TAKE_FOCUS", False);
118         m_wm_state= XInternAtom(m_display, "WM_STATE", False);
119         m_wm_change_state= XInternAtom(m_display, "WM_CHANGE_STATE", False);
120         m_net_state= XInternAtom(m_display, "_NET_WM_STATE", False);
121         m_net_max_horz= XInternAtom(m_display,
122                                         "_NET_WM_STATE_MAXIMIZED_HORZ", False);
123         m_net_max_vert= XInternAtom(m_display,
124                                         "_NET_WM_STATE_MAXIMIZED_VERT", False);
125         m_net_fullscreen= XInternAtom(m_display,
126                                         "_NET_WM_STATE_FULLSCREEN", False);
127         m_motif= XInternAtom(m_display, "_MOTIF_WM_HINTS", False);
128         m_targets= XInternAtom(m_display, "TARGETS", False);
129         m_string= XInternAtom(m_display, "STRING", False);
130         m_compound_text= XInternAtom(m_display, "COMPOUND_TEXT", False);
131         m_text= XInternAtom(m_display, "TEXT", False);
132         m_clipboard= XInternAtom(m_display, "CLIPBOARD", False);
133         m_primary= XInternAtom(m_display, "PRIMARY", False);
134         m_xclip_out= XInternAtom(m_display, "XCLIP_OUT", False);
135         m_incr= XInternAtom(m_display, "INCR", False);
136         m_utf8_string= XInternAtom(m_display, "UTF8_STRING", False);
137         m_last_warp = 0;
138
139
140         // compute the initial time
141         timeval tv;
142         if (gettimeofday(&tv,NULL) == -1) {
143                 GHOST_ASSERT(false,"Could not instantiate timer!");
144         }
145
146         m_start_time = GHOST_TUns64(tv.tv_sec*1000 + tv.tv_usec/1000);
147         
148         
149         /* use detectable autorepeat, mac and windows also do this */
150         int use_xkb;
151         int xkb_opcode, xkb_event, xkb_error;
152         int xkb_major = XkbMajorVersion, xkb_minor = XkbMinorVersion;
153         
154         use_xkb = XkbQueryExtension(m_display, &xkb_opcode, &xkb_event, &xkb_error, &xkb_major, &xkb_minor);
155         if (use_xkb) {
156                 XkbSetDetectableAutoRepeat(m_display, true, NULL);
157         }
158         
159 }
160
161 GHOST_SystemX11::
162 ~GHOST_SystemX11()
163 {
164         XCloseDisplay(m_display);
165 }
166
167
168         GHOST_TSuccess 
169 GHOST_SystemX11::
170 init(
171 ){
172         GHOST_TSuccess success = GHOST_System::init();
173
174         if (success) {
175
176                 m_ndofManager = new GHOST_NDOFManagerX11(*this);
177
178                 m_displayManager = new GHOST_DisplayManagerX11(this);
179
180                 if (m_displayManager) {
181                         return GHOST_kSuccess;
182                 }
183         }
184
185         return GHOST_kFailure;
186 }
187
188         GHOST_TUns64
189 GHOST_SystemX11::
190 getMilliSeconds(
191 ) const {
192         timeval tv;
193         if (gettimeofday(&tv,NULL) == -1) {
194                 GHOST_ASSERT(false,"Could not compute time!");
195         }
196
197         return  GHOST_TUns64(tv.tv_sec*1000 + tv.tv_usec/1000) - m_start_time;
198 }
199         
200         GHOST_TUns8 
201 GHOST_SystemX11::
202 getNumDisplays(
203 ) const {
204         return GHOST_TUns8(1);
205 }
206
207         /**
208          * Returns the dimensions of the main display on this system.
209          * @return The dimension of the main display.
210          */
211         void 
212 GHOST_SystemX11::
213 getMainDisplayDimensions(
214         GHOST_TUns32& width,
215         GHOST_TUns32& height
216 ) const {       
217         if (m_display) {
218                 width  = DisplayWidth(m_display, DefaultScreen(m_display));
219                 height = DisplayHeight(m_display, DefaultScreen(m_display));
220         }
221 }
222
223         /**
224          * Create a new window.
225          * The new window is added to the list of windows managed.
226          * Never explicitly delete the window, use disposeWindow() instead.
227          * @param       title   The name of the window (displayed in the title bar of the window if the OS supports it).
228          * @param       left    The coordinate of the left edge of the window.
229          * @param       top             The coordinate of the top edge of the window.
230          * @param       width   The width the window.
231          * @param       height  The height the window.
232          * @param       state   The state of the window when opened.
233          * @param       type    The type of drawing context installed in this window.
234          * @param       stereoVisual    Stereo visual for quad buffered stereo.
235          * @param       numOfAASamples  Number of samples used for AA (zero if no AA)
236          * @param       parentWindow    Parent (embedder) window
237          * @return      The new window (or 0 if creation failed).
238          */
239         GHOST_IWindow* 
240 GHOST_SystemX11::
241 createWindow(
242         const STR_String& title,
243         GHOST_TInt32 left,
244         GHOST_TInt32 top,
245         GHOST_TUns32 width,
246         GHOST_TUns32 height,
247         GHOST_TWindowState state,
248         GHOST_TDrawingContextType type,
249         bool stereoVisual,
250         const GHOST_TUns16 numOfAASamples,
251         const GHOST_TEmbedderWindowID parentWindow
252 ){
253         GHOST_WindowX11 * window = 0;
254         
255         if (!m_display) return 0;
256
257         window = new GHOST_WindowX11 (
258                 this,m_display,title, left, top, width, height, state, parentWindow, type, stereoVisual
259         );
260
261         if (window) {
262                 // Both are now handle in GHOST_WindowX11.cpp
263                 // Focus and Delete atoms.
264
265                 if (window->getValid()) {
266                         // Store the pointer to the window 
267                         m_windowManager->addWindow(window);
268                         
269                         pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window) );
270                 }
271                 else {
272                         delete window;
273                         window = 0;
274                 }
275         }
276         return window;
277 }
278
279         GHOST_WindowX11 * 
280 GHOST_SystemX11::
281 findGhostWindow(
282         Window xwind
283 ) const {
284         
285         if (xwind == 0) return NULL;
286
287         // It is not entirely safe to do this as the backptr may point
288         // to a window that has recently been removed. 
289         // We should always check the window manager's list of windows 
290         // and only process events on these windows.
291
292         vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();
293
294         vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
295         vector<GHOST_IWindow *>::const_iterator win_end = win_vec.end();
296         
297         for (; win_it != win_end; ++win_it) {
298                 GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
299                 if (window->getXWindow() == xwind) {
300                         return window;
301                 }
302         }
303         return NULL;
304         
305 }
306
307 static void SleepTillEvent(Display *display, GHOST_TInt64 maxSleep) {
308         int fd = ConnectionNumber(display);
309         fd_set fds;
310         
311         FD_ZERO(&fds);
312         FD_SET(fd, &fds);
313
314         if (maxSleep == -1) {
315             select(fd + 1, &fds, NULL, NULL, NULL);
316         } else {
317                 timeval tv;
318
319                 tv.tv_sec = maxSleep/1000;
320                 tv.tv_usec = (maxSleep - tv.tv_sec*1000)*1000;
321         
322             select(fd + 1, &fds, NULL, NULL, &tv);
323         }
324 }
325
326 /* This function borrowed from Qt's X11 support
327  * qclipboard_x11.cpp
328  *  */
329 struct init_timestamp_data
330 {
331     Time timestamp;
332 };
333
334 static Bool init_timestamp_scanner(Display*, XEvent *event, XPointer arg)
335 {
336         init_timestamp_data *data =
337         reinterpret_cast<init_timestamp_data*>(arg);
338     switch(event->type)
339     {
340     case ButtonPress:
341     case ButtonRelease:
342         data->timestamp = event->xbutton.time;
343         break;
344     case MotionNotify:
345         data->timestamp = event->xmotion.time;
346         break;
347     case KeyPress:
348     case KeyRelease:
349         data->timestamp = event->xkey.time;
350         break;
351     case PropertyNotify:
352         data->timestamp = event->xproperty.time;
353         break;
354     case EnterNotify:
355     case LeaveNotify:
356         data->timestamp = event->xcrossing.time;
357         break;
358     case SelectionClear:
359         data->timestamp = event->xselectionclear.time;
360         break;
361     default:
362         break;
363     }
364
365     return false;
366 }
367
368 Time
369 GHOST_SystemX11::
370 lastEventTime(Time default_time) {
371     init_timestamp_data data;
372     data.timestamp = default_time;
373     XEvent ev;
374     XCheckIfEvent(m_display, &ev, &init_timestamp_scanner, (XPointer)&data);
375
376     return data.timestamp;
377 }
378
379
380
381         bool 
382 GHOST_SystemX11::
383 processEvents(
384         bool waitForEvent
385 ){
386         // Get all the current events -- translate them into 
387         // ghost events and call base class pushEvent() method.
388         
389         bool anyProcessed = false;
390         
391         do {
392                 GHOST_TimerManager* timerMgr = getTimerManager();
393                 
394                 if (waitForEvent && m_dirty_windows.empty() && !XPending(m_display)) {
395                         GHOST_TUns64 next = timerMgr->nextFireTime();
396                         
397                         if (next==GHOST_kFireTimeNever) {
398                                 SleepTillEvent(m_display, -1);
399                         } else {
400                                 GHOST_TInt64 maxSleep = next - getMilliSeconds();
401
402                                 if(maxSleep >= 0)
403                                         SleepTillEvent(m_display, next - getMilliSeconds());
404                         }
405                 }
406                 
407                 if (timerMgr->fireTimers(getMilliSeconds())) {
408                         anyProcessed = true;
409                 }
410                 
411                 while (XPending(m_display)) {
412                         XEvent xevent;
413                         XNextEvent(m_display, &xevent);
414                         processEvent(&xevent);
415                         anyProcessed = true;
416                 }
417                 
418                 if (generateWindowExposeEvents()) {
419                         anyProcessed = true;
420                 }
421         } while (waitForEvent && !anyProcessed);
422         
423         return anyProcessed;
424 }
425
426         void
427 GHOST_SystemX11::processEvent(XEvent *xe)
428 {
429         GHOST_WindowX11 * window = findGhostWindow(xe->xany.window);    
430         GHOST_Event * g_event = NULL;
431
432         if (!window) {
433                 return;
434         }
435         
436         switch (xe->type) {
437                 case Expose:
438                 {
439                         XExposeEvent & xee = xe->xexpose;
440
441                         if (xee.count == 0) {
442                                 // Only generate a single expose event
443                                 // per read of the event queue.
444
445                                 g_event = new
446                                 GHOST_Event(
447                                         getMilliSeconds(),
448                                         GHOST_kEventWindowUpdate,
449                                         window
450                                 );
451                         }
452                         break;
453                 }
454
455                 case MotionNotify:
456                 {
457                         XMotionEvent &xme = xe->xmotion;
458                         
459                         if(window->getCursorGrabMode() != GHOST_kGrabDisable && window->getCursorGrabMode() != GHOST_kGrabNormal)
460                         {
461                                 GHOST_TInt32 x_new= xme.x_root;
462                                 GHOST_TInt32 y_new= xme.y_root;
463                                 GHOST_TInt32 x_accum, y_accum;
464                                 GHOST_Rect bounds;
465
466                                 /* fallback to window bounds */
467                                 if(window->getCursorGrabBounds(bounds)==GHOST_kFailure)
468                                         window->getClientBounds(bounds);
469
470                                 /* could also clamp to screen bounds
471                                  * wrap with a window outside the view will fail atm  */
472                                 bounds.wrapPoint(x_new, y_new, 8); /* offset of one incase blender is at screen bounds */
473                                 window->getCursorGrabAccum(x_accum, y_accum);
474
475                                 if(x_new != xme.x_root || y_new != xme.y_root) {
476                                         if (xme.time > m_last_warp) {
477                                                 /* when wrapping we don't need to add an event because the
478                                                  * setCursorPosition call will cause a new event after */
479                                                 setCursorPosition(x_new, y_new); /* wrap */
480                                                 window->setCursorGrabAccum(x_accum + (xme.x_root - x_new), y_accum + (xme.y_root - y_new));
481                                                 m_last_warp = lastEventTime(xme.time);
482                                         } else {
483                                                 setCursorPosition(x_new, y_new); /* wrap but don't accumulate */
484                                         }
485                                 }
486                                 else {
487                                         g_event = new
488                                         GHOST_EventCursor(
489                                                 getMilliSeconds(),
490                                                 GHOST_kEventCursorMove,
491                                                 window,
492                                                 xme.x_root + x_accum,
493                                                 xme.y_root + y_accum
494                                         );
495                                 }
496                         }
497                         else {
498                                 g_event = new
499                                 GHOST_EventCursor(
500                                         getMilliSeconds(),
501                                         GHOST_kEventCursorMove,
502                                         window,
503                                         xme.x_root,
504                                         xme.y_root
505                                 );
506                         }
507                         break;
508                 }
509
510                 case KeyPress:
511                 case KeyRelease:
512                 {
513                         XKeyEvent *xke = &(xe->xkey);
514                 
515                         KeySym key_sym = XLookupKeysym(xke,0);
516                         char ascii;
517                         
518                         GHOST_TKey gkey = convertXKey(key_sym);
519                         GHOST_TEventType type = (xke->type == KeyPress) ? 
520                                 GHOST_kEventKeyDown : GHOST_kEventKeyUp;
521                         
522                         if (!XLookupString(xke, &ascii, 1, NULL, NULL)) {
523                                 ascii = '\0';
524                         }
525                         
526                         g_event = new
527                         GHOST_EventKey(
528                                 getMilliSeconds(),
529                                 type,
530                                 window,
531                                 gkey,
532                                 ascii
533                         );
534                         
535                 break;
536                 }
537
538                 case ButtonPress:
539                 case ButtonRelease:
540                 {
541                         XButtonEvent & xbe = xe->xbutton;
542                         GHOST_TButtonMask gbmask = GHOST_kButtonMaskLeft;
543                         GHOST_TEventType type = (xbe.type == ButtonPress) ? 
544                                 GHOST_kEventButtonDown : GHOST_kEventButtonUp;
545
546                         /* process wheel mouse events and break, only pass on press events */
547                         if(xbe.button == Button4) {
548                                 if(xbe.type == ButtonPress)
549                                         g_event = new GHOST_EventWheel(getMilliSeconds(), window, 1);
550                                 break;
551                         }
552                         else if(xbe.button == Button5) {
553                                 if(xbe.type == ButtonPress)
554                                         g_event = new GHOST_EventWheel(getMilliSeconds(), window, -1);
555                                 break;
556                         }
557                         
558                         /* process rest of normal mouse buttons */
559                         if(xbe.button == Button1)
560                                 gbmask = GHOST_kButtonMaskLeft;
561                         else if(xbe.button == Button2)
562                                 gbmask = GHOST_kButtonMaskMiddle;
563                         else if(xbe.button == Button3)
564                                 gbmask = GHOST_kButtonMaskRight;
565                         /* It seems events 6 and 7 are for horizontal scrolling.
566                         * you can re-order button mapping like this... (swaps 6,7 with 8,9)
567                         *   xmodmap -e "pointer = 1 2 3 4 5 8 9 6 7" 
568                         */
569                         else if(xbe.button == 8)
570                                 gbmask = GHOST_kButtonMaskButton4;
571                         else if(xbe.button == 9)
572                                 gbmask = GHOST_kButtonMaskButton5;
573                         else
574                                 break;
575
576                         g_event = new
577                         GHOST_EventButton(
578                                 getMilliSeconds(),
579                                 type,
580                                 window,
581                                 gbmask
582                         );
583                         break;
584                 }
585                         
586                         // change of size, border, layer etc.
587                 case ConfigureNotify:
588                 {
589                         /* XConfigureEvent & xce = xe->xconfigure; */
590
591                         g_event = new 
592                         GHOST_Event(
593                                 getMilliSeconds(),
594                                 GHOST_kEventWindowSize,
595                                 window
596                         );                      
597                         break;
598                 }
599
600                 case FocusIn:
601                 case FocusOut:
602                 {
603                         XFocusChangeEvent &xfe = xe->xfocus;
604                 
605                         // May have to look at the type of event and filter some
606                         // out.
607                                                                         
608                         GHOST_TEventType gtype = (xfe.type == FocusIn) ? 
609                                 GHOST_kEventWindowActivate : GHOST_kEventWindowDeactivate;
610
611                         g_event = new 
612                         GHOST_Event(    
613                                 getMilliSeconds(),
614                                 gtype,
615                                 window
616                         );
617                         break;
618
619                 }
620                 case ClientMessage:
621                 {
622                         XClientMessageEvent & xcme = xe->xclient;
623
624 #ifndef __sgi                   
625                         if (((Atom)xcme.data.l[0]) == m_delete_window_atom) {
626                                 g_event = new 
627                                 GHOST_Event(    
628                                         getMilliSeconds(),
629                                         GHOST_kEventWindowClose,
630                                         window
631                                 );
632                         } else 
633 #endif
634                         if (sNdofInfo.currValues) {
635 //                              static GHOST_TEventNDOFData data = {0,0,0,0,0,0,0,0,0,0,0};
636                                 if (xcme.message_type == sNdofInfo.motionAtom)
637                                 {
638 //                                      data.changed = 1;
639 //                                      data.delta = xcme.data.s[8] - data.time;
640 //                                      data.time = xcme.data.s[8];
641 //                                      data.tx = xcme.data.s[2] >> 2;
642 //                                      data.ty = xcme.data.s[3] >> 2;
643 //                                      data.tz = xcme.data.s[4] >> 2;
644 //                                      data.rx = xcme.data.s[5];
645 //                                      data.ry = xcme.data.s[6];
646 //                                      data.rz =-xcme.data.s[7];
647                                                 
648                                         short t[3], r[3];
649                                         t[0] = xcme.data.s[2] >> 2;
650                                         t[1] = xcme.data.s[3] >> 2;
651                                         t[2] = xcme.data.s[4] >> 2;
652                                         r[0] = xcme.data.s[5];
653                                         r[1] = xcme.data.s[6];
654                                         r[2] =-xcme.data.s[7];
655
656                                         // [mce] look into this soon, as in find out why some values
657                                         // are shifted and where this message originates.
658
659                                         m_ndofManager->updateTranslation(t, getMilliSeconds());
660                                         m_ndofManager->updateRotation(r, getMilliSeconds());
661
662 //                                      g_event = new GHOST_EventNDOF(getMilliSeconds(),
663 //                                                                    GHOST_kEventNDOFMotion,
664 //                                                                    window, data);
665
666                                 } else if (xcme.message_type == sNdofInfo.btnPressAtom) {
667 //                                      data.changed = 2;
668 //                                      data.delta = xcme.data.s[8] - data.time;
669 //                                      data.time = xcme.data.s[8];
670 //                                      data.buttons = xcme.data.s[2];
671
672                                         unsigned short buttons = xcme.data.s[2];
673                                         m_ndofManager->updateButtons(buttons, getMilliSeconds());
674
675 //                                      g_event = new GHOST_EventNDOF(getMilliSeconds(),
676 //                                                                    GHOST_kEventNDOFButton,
677 //                                                                    window, data);
678                                 }
679                         } else if (((Atom)xcme.data.l[0]) == m_wm_take_focus) {
680                                 XWindowAttributes attr;
681                                 Window fwin;
682                                 int revert_to;
683
684                                 /* as ICCCM say, we need reply this event
685                                  * with a SetInputFocus, the data[1] have
686                                  * the valid timestamp (send by the wm).
687                                  *
688                                  * Some WM send this event before the
689                                  * window is really mapped (for example
690                                  * change from virtual desktop), so we need
691                                  * to be sure that our windows is mapped
692                                  * or this call fail and close blender.
693                                  */
694                                 if (XGetWindowAttributes(m_display, xcme.window, &attr) == True) {
695                                         if (XGetInputFocus(m_display, &fwin, &revert_to) == True) {
696                                                 if (attr.map_state == IsViewable) {
697                                                         if (fwin != xcme.window)
698                                                                 XSetInputFocus(m_display, xcme.window, RevertToParent, xcme.data.l[1]);
699                                                 }
700                                         }
701                                 }
702                         } else {
703                                 /* Unknown client message, ignore */
704                         }
705                         break;
706                 }
707                 
708                 case DestroyNotify:
709                         ::exit(-1);     
710                 // We're not interested in the following things.(yet...)
711                 case NoExpose : 
712                 case GraphicsExpose :
713                         break;
714                 
715                 case EnterNotify:
716                 case LeaveNotify:
717                 {
718                         // XCrossingEvents pointer leave enter window.
719                         // also do cursor move here, MotionNotify only
720                         // happens when motion starts & ends inside window
721                         XCrossingEvent &xce = xe->xcrossing;
722                         
723                         g_event = new 
724                         GHOST_EventCursor(
725                                 getMilliSeconds(),
726                                 GHOST_kEventCursorMove,
727                                 window,
728                                 xce.x_root,
729                                 xce.y_root
730                         );
731                         break;
732                 }
733                 case MapNotify:
734                         /*
735                          * From ICCCM:
736                          * [ Clients can select for StructureNotify on their
737                          *   top-level windows to track transition between
738                          *   Normal and Iconic states. Receipt of a MapNotify
739                          *   event will indicate a transition to the Normal
740                          *   state, and receipt of an UnmapNotify event will
741                          *   indicate a transition to the Iconic state. ]
742                          */
743                         if (window->m_post_init == True) {
744                                 /*
745                                  * Now we are sure that the window is
746                                  * mapped, so only need change the state.
747                                  */
748                                 window->setState (window->m_post_state);
749                                 window->m_post_init = False;
750                         }
751                         break;
752                 case UnmapNotify:
753                         break;
754                 case MappingNotify:
755                 case ReparentNotify:
756                         break;
757                 case SelectionRequest:
758                 {
759                         XEvent nxe;
760                         Atom target, string, compound_text, c_string;
761                         XSelectionRequestEvent *xse = &xe->xselectionrequest;
762                         
763                         target = XInternAtom(m_display, "TARGETS", False);
764                         string = XInternAtom(m_display, "STRING", False);
765                         compound_text = XInternAtom(m_display, "COMPOUND_TEXT", False);
766                         c_string = XInternAtom(m_display, "C_STRING", False);
767                         
768                         /* support obsolete clients */
769                         if (xse->property == None) {
770                                 xse->property = xse->target;
771                         }
772                         
773                         nxe.xselection.type = SelectionNotify;
774                         nxe.xselection.requestor = xse->requestor;
775                         nxe.xselection.property = xse->property;
776                         nxe.xselection.display = xse->display;
777                         nxe.xselection.selection = xse->selection;
778                         nxe.xselection.target = xse->target;
779                         nxe.xselection.time = xse->time;
780                         
781                         /*Check to see if the requestor is asking for String*/
782                         if(xse->target == string || xse->target == compound_text || xse->target == c_string) {
783                                 if (xse->selection == XInternAtom(m_display, "PRIMARY", False)) {
784                                         XChangeProperty(m_display, xse->requestor, xse->property, xse->target, 8, PropModeReplace, (unsigned char*)txt_select_buffer, strlen(txt_select_buffer));
785                                 } else if (xse->selection == XInternAtom(m_display, "CLIPBOARD", False)) {
786                                         XChangeProperty(m_display, xse->requestor, xse->property, xse->target, 8, PropModeReplace, (unsigned char*)txt_cut_buffer, strlen(txt_cut_buffer));
787                                 }
788                         } else if (xse->target == target) {
789                                 Atom alist[4];
790                                 alist[0] = target;
791                                 alist[1] = string;
792                                 alist[2] = compound_text;
793                                 alist[3] = c_string;
794                                 XChangeProperty(m_display, xse->requestor, xse->property, xse->target, 32, PropModeReplace, (unsigned char*)alist, 4);
795                                 XFlush(m_display);
796                         } else  {
797                                 //Change property to None because we do not support anything but STRING
798                                 nxe.xselection.property = None;
799                         }
800                         
801                         //Send the event to the client 0 0 == False, SelectionNotify
802                         XSendEvent(m_display, xse->requestor, 0, 0, &nxe);
803                         XFlush(m_display);
804                         break;
805                 }
806                 
807                 default: {
808                         if(xe->type == window->GetXTablet().MotionEvent) 
809                         {
810                                 XDeviceMotionEvent* data = (XDeviceMotionEvent*)xe;
811                                 window->GetXTablet().CommonData.Pressure= 
812                                         data->axis_data[2]/((float)window->GetXTablet().PressureLevels);
813                         
814                         /* the (short) cast and the &0xffff is bizarre and unexplained anywhere,
815                          * but I got garbage data without it. Found it in the xidump.c source --matt */
816                                 window->GetXTablet().CommonData.Xtilt= 
817                                         (short)(data->axis_data[3]&0xffff)/((float)window->GetXTablet().XtiltLevels);
818                                 window->GetXTablet().CommonData.Ytilt= 
819                                         (short)(data->axis_data[4]&0xffff)/((float)window->GetXTablet().YtiltLevels);
820                         }
821                         else if(xe->type == window->GetXTablet().ProxInEvent) 
822                         {
823                                 XProximityNotifyEvent* data = (XProximityNotifyEvent*)xe;
824                                 if(data->deviceid == window->GetXTablet().StylusID)
825                                         window->GetXTablet().CommonData.Active= GHOST_kTabletModeStylus;
826                                 else if(data->deviceid == window->GetXTablet().EraserID)
827                                         window->GetXTablet().CommonData.Active= GHOST_kTabletModeEraser;
828                         }
829                         else if(xe->type == window->GetXTablet().ProxOutEvent)
830                                 window->GetXTablet().CommonData.Active= GHOST_kTabletModeNone;
831
832                         break;
833                 }
834         }
835
836         if (g_event) {
837                 pushEvent(g_event);
838         }
839 }
840
841 /*
842         void *
843 GHOST_SystemX11::
844 prepareNdofInfo(volatile GHOST_TEventNDOFData *currentNdofValues)
845 {
846         const vector<GHOST_IWindow*>& v(m_windowManager->getWindows());
847         if (v.size() > 0)
848                 sNdofInfo.window = static_cast<GHOST_WindowX11*>(v[0])->getXWindow();
849         sNdofInfo.display = m_display;
850         sNdofInfo.currValues = currentNdofValues;
851         return (void*)&sNdofInfo;
852 }
853 */
854
855         GHOST_TSuccess 
856 GHOST_SystemX11::
857 getModifierKeys(
858         GHOST_ModifierKeys& keys
859 ) const {
860
861         // analyse the masks retuned from XQueryPointer.
862
863         memset((void *)m_keyboard_vector,0,sizeof(m_keyboard_vector));
864
865         XQueryKeymap(m_display,(char *)m_keyboard_vector);
866
867         // now translate key symobols into keycodes and
868         // test with vector.
869
870         const KeyCode shift_l = XKeysymToKeycode(m_display,XK_Shift_L);
871         const KeyCode shift_r = XKeysymToKeycode(m_display,XK_Shift_R);
872         const KeyCode control_l = XKeysymToKeycode(m_display,XK_Control_L);
873         const KeyCode control_r = XKeysymToKeycode(m_display,XK_Control_R);
874         const KeyCode alt_l = XKeysymToKeycode(m_display,XK_Alt_L);
875         const KeyCode alt_r = XKeysymToKeycode(m_display,XK_Alt_R);
876
877         // Shift
878         if ((m_keyboard_vector[shift_l >> 3] >> (shift_l & 7)) & 1) {
879                 keys.set(GHOST_kModifierKeyLeftShift,true);
880         } else {
881                 keys.set(GHOST_kModifierKeyLeftShift,false);
882         }
883         if ((m_keyboard_vector[shift_r >> 3] >> (shift_r & 7)) & 1) {
884
885                 keys.set(GHOST_kModifierKeyRightShift,true);
886         } else {
887                 keys.set(GHOST_kModifierKeyRightShift,false);
888         }
889
890         // control (weep)
891         if ((m_keyboard_vector[control_l >> 3] >> (control_l & 7)) & 1) {
892                 keys.set(GHOST_kModifierKeyLeftControl,true);
893         } else {
894                 keys.set(GHOST_kModifierKeyLeftControl,false);
895         }
896         if ((m_keyboard_vector[control_r >> 3] >> (control_r & 7)) & 1) {
897                 keys.set(GHOST_kModifierKeyRightControl,true);
898         } else {
899                 keys.set(GHOST_kModifierKeyRightControl,false);
900         }
901
902         // Alt (yawn)
903         if ((m_keyboard_vector[alt_l >> 3] >> (alt_l & 7)) & 1) {
904                 keys.set(GHOST_kModifierKeyLeftAlt,true);
905         } else {
906                 keys.set(GHOST_kModifierKeyLeftAlt,false);
907         }       
908         if ((m_keyboard_vector[alt_r >> 3] >> (alt_r & 7)) & 1) {
909                 keys.set(GHOST_kModifierKeyRightAlt,true);
910         } else {
911                 keys.set(GHOST_kModifierKeyRightAlt,false);
912         }
913         return GHOST_kSuccess;
914 }
915
916         GHOST_TSuccess 
917 GHOST_SystemX11::
918 getButtons(
919         GHOST_Buttons& buttons
920 ) const {
921
922         Window root_return, child_return;
923         int rx,ry,wx,wy;
924         unsigned int mask_return;
925
926         if (XQueryPointer(
927                 m_display,
928                 RootWindow(m_display,DefaultScreen(m_display)),
929                 &root_return,
930                 &child_return,
931                 &rx,&ry,
932                 &wx,&wy,
933                 &mask_return
934         ) == False) {
935                 return GHOST_kFailure;
936         } else {
937
938                 if (mask_return & Button1Mask) {
939                         buttons.set(GHOST_kButtonMaskLeft,true);
940                 } else {
941                         buttons.set(GHOST_kButtonMaskLeft,false);
942                 }
943
944                 if (mask_return & Button2Mask) {
945                         buttons.set(GHOST_kButtonMaskMiddle,true);
946                 } else {
947                         buttons.set(GHOST_kButtonMaskMiddle,false);
948                 }
949
950                 if (mask_return & Button3Mask) {
951                         buttons.set(GHOST_kButtonMaskRight,true);
952                 } else {
953                         buttons.set(GHOST_kButtonMaskRight,false);
954                 }
955         }       
956
957         return GHOST_kSuccess;
958 }
959
960
961         GHOST_TSuccess 
962 GHOST_SystemX11::
963 getCursorPosition(
964         GHOST_TInt32& x,
965         GHOST_TInt32& y
966 ) const {
967
968         Window root_return, child_return;
969         int rx,ry,wx,wy;
970         unsigned int mask_return;
971
972         if (XQueryPointer(
973                 m_display,
974                 RootWindow(m_display,DefaultScreen(m_display)),
975                 &root_return,
976                 &child_return,
977                 &rx,&ry,
978                 &wx,&wy,
979                 &mask_return
980         ) == False) {
981                 return GHOST_kFailure;
982         } else {
983                 x = rx;
984                 y = ry;
985         }       
986         return GHOST_kSuccess;
987 }
988
989
990         GHOST_TSuccess 
991 GHOST_SystemX11::
992 setCursorPosition(
993         GHOST_TInt32 x,
994         GHOST_TInt32 y
995 ) {
996
997         // This is a brute force move in screen coordinates
998         // XWarpPointer does relative moves so first determine the
999         // current pointer position.
1000
1001         int cx,cy;
1002         if (getCursorPosition(cx,cy) == GHOST_kFailure) {
1003                 return GHOST_kFailure;
1004         }
1005
1006         int relx = x-cx;
1007         int rely = y-cy;
1008
1009         XWarpPointer(m_display,None,None,0,0,0,0,relx,rely);
1010         XSync(m_display, 0); /* Sync to process all requests */
1011         
1012         return GHOST_kSuccess;
1013 }
1014
1015
1016         void
1017 GHOST_SystemX11::
1018 addDirtyWindow(
1019         GHOST_WindowX11 * bad_wind
1020 ){
1021
1022         GHOST_ASSERT((bad_wind != NULL), "addDirtyWindow() NULL ptr trapped (window)");
1023         
1024         m_dirty_windows.push_back(bad_wind);
1025 }
1026
1027
1028         bool
1029 GHOST_SystemX11::
1030 generateWindowExposeEvents(
1031 ){
1032
1033         vector<GHOST_WindowX11 *>::iterator w_start = m_dirty_windows.begin();
1034         vector<GHOST_WindowX11 *>::const_iterator w_end = m_dirty_windows.end();
1035         bool anyProcessed = false;
1036         
1037         for (;w_start != w_end; ++w_start) {
1038                 GHOST_Event * g_event = new 
1039                         GHOST_Event(
1040                                 getMilliSeconds(),
1041                                 GHOST_kEventWindowUpdate,
1042                                 *w_start
1043                         );                      
1044
1045                 (*w_start)->validate(); 
1046                 
1047                 if (g_event) {
1048                         pushEvent(g_event);
1049                         anyProcessed = true;
1050                 }
1051         }
1052
1053         m_dirty_windows.clear();
1054         return anyProcessed;
1055 }
1056
1057 #define GXMAP(k,x,y) case x: k = y; break; 
1058
1059         GHOST_TKey
1060 GHOST_SystemX11::
1061 convertXKey(
1062         KeySym key
1063 ){
1064         GHOST_TKey type;
1065
1066         if ((key >= XK_A) && (key <= XK_Z)) {
1067                 type = GHOST_TKey( key - XK_A + int(GHOST_kKeyA));
1068         } else if ((key >= XK_a) && (key <= XK_z)) {
1069                 type = GHOST_TKey(key - XK_a + int(GHOST_kKeyA));
1070         } else if ((key >= XK_0) && (key <= XK_9)) {
1071                 type = GHOST_TKey(key - XK_0 + int(GHOST_kKey0));
1072         } else if ((key >= XK_F1) && (key <= XK_F24)) {
1073                 type = GHOST_TKey(key - XK_F1 + int(GHOST_kKeyF1));
1074 #if defined(__sun) || defined(__sun__) 
1075                 /* This is a bit of a hack, but it looks like sun
1076                    Used F11 and friends for its special keys Stop,again etc..
1077                    So this little patch enables F11 and F12 to work as expected
1078                    following link has documentation on it: 
1079                    http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4734408
1080                    also from /usr/include/X11/Sunkeysym.h 
1081 #define SunXK_F36               0x1005FF10      // Labeled F11
1082 #define SunXK_F37               0x1005FF11      // Labeled F12 
1083
1084                                 mein@cs.umn.edu
1085                  */
1086                 
1087         } else if (key == 268828432) {
1088                 type = GHOST_kKeyF11;
1089         } else if (key == 268828433) {
1090                 type = GHOST_kKeyF12;
1091 #endif
1092         } else {
1093                 switch(key) {
1094                         GXMAP(type,XK_BackSpace,        GHOST_kKeyBackSpace);
1095                         GXMAP(type,XK_Tab,              GHOST_kKeyTab);
1096                         GXMAP(type,XK_Return,           GHOST_kKeyEnter);
1097                         GXMAP(type,XK_Escape,           GHOST_kKeyEsc);
1098                         GXMAP(type,XK_space,            GHOST_kKeySpace);
1099                         
1100                         GXMAP(type,XK_Linefeed,         GHOST_kKeyLinefeed);
1101                         GXMAP(type,XK_semicolon,        GHOST_kKeySemicolon);
1102                         GXMAP(type,XK_period,           GHOST_kKeyPeriod);
1103                         GXMAP(type,XK_comma,            GHOST_kKeyComma);
1104                         GXMAP(type,XK_quoteright,       GHOST_kKeyQuote);
1105                         GXMAP(type,XK_quoteleft,        GHOST_kKeyAccentGrave);
1106                         GXMAP(type,XK_minus,            GHOST_kKeyMinus);
1107                         GXMAP(type,XK_slash,            GHOST_kKeySlash);
1108                         GXMAP(type,XK_backslash,        GHOST_kKeyBackslash);
1109                         GXMAP(type,XK_equal,            GHOST_kKeyEqual);
1110                         GXMAP(type,XK_bracketleft,      GHOST_kKeyLeftBracket);
1111                         GXMAP(type,XK_bracketright,     GHOST_kKeyRightBracket);
1112                         GXMAP(type,XK_Pause,            GHOST_kKeyPause);
1113                         
1114                         GXMAP(type,XK_Shift_L,          GHOST_kKeyLeftShift);
1115                         GXMAP(type,XK_Shift_R,          GHOST_kKeyRightShift);
1116                         GXMAP(type,XK_Control_L,        GHOST_kKeyLeftControl);
1117                         GXMAP(type,XK_Control_R,        GHOST_kKeyRightControl);
1118                         GXMAP(type,XK_Alt_L,            GHOST_kKeyLeftAlt);
1119                         GXMAP(type,XK_Alt_R,            GHOST_kKeyRightAlt);
1120
1121                         GXMAP(type,XK_Insert,           GHOST_kKeyInsert);
1122                         GXMAP(type,XK_Delete,           GHOST_kKeyDelete);
1123                         GXMAP(type,XK_Home,                     GHOST_kKeyHome);
1124                         GXMAP(type,XK_End,                      GHOST_kKeyEnd);
1125                         GXMAP(type,XK_Page_Up,          GHOST_kKeyUpPage);
1126                         GXMAP(type,XK_Page_Down,        GHOST_kKeyDownPage);
1127
1128                         GXMAP(type,XK_Left,                     GHOST_kKeyLeftArrow);
1129                         GXMAP(type,XK_Right,            GHOST_kKeyRightArrow);
1130                         GXMAP(type,XK_Up,                       GHOST_kKeyUpArrow);
1131                         GXMAP(type,XK_Down,                     GHOST_kKeyDownArrow);
1132
1133                         GXMAP(type,XK_Caps_Lock,        GHOST_kKeyCapsLock);
1134                         GXMAP(type,XK_Scroll_Lock,      GHOST_kKeyScrollLock);
1135                         GXMAP(type,XK_Num_Lock,         GHOST_kKeyNumLock);
1136                         
1137                                 /* keypad events */
1138                                 
1139                         GXMAP(type,XK_KP_0,                     GHOST_kKeyNumpad0);
1140                         GXMAP(type,XK_KP_1,                     GHOST_kKeyNumpad1);
1141                         GXMAP(type,XK_KP_2,                     GHOST_kKeyNumpad2);
1142                         GXMAP(type,XK_KP_3,                     GHOST_kKeyNumpad3);
1143                         GXMAP(type,XK_KP_4,                     GHOST_kKeyNumpad4);
1144                         GXMAP(type,XK_KP_5,                     GHOST_kKeyNumpad5);
1145                         GXMAP(type,XK_KP_6,                     GHOST_kKeyNumpad6);
1146                         GXMAP(type,XK_KP_7,                     GHOST_kKeyNumpad7);
1147                         GXMAP(type,XK_KP_8,                     GHOST_kKeyNumpad8);
1148                         GXMAP(type,XK_KP_9,                     GHOST_kKeyNumpad9);
1149                         GXMAP(type,XK_KP_Decimal,       GHOST_kKeyNumpadPeriod);
1150
1151                         GXMAP(type,XK_KP_Insert,        GHOST_kKeyNumpad0);
1152                         GXMAP(type,XK_KP_End,           GHOST_kKeyNumpad1);
1153                         GXMAP(type,XK_KP_Down,          GHOST_kKeyNumpad2);
1154                         GXMAP(type,XK_KP_Page_Down,     GHOST_kKeyNumpad3);
1155                         GXMAP(type,XK_KP_Left,          GHOST_kKeyNumpad4);
1156                         GXMAP(type,XK_KP_Begin,         GHOST_kKeyNumpad5);
1157                         GXMAP(type,XK_KP_Right,         GHOST_kKeyNumpad6);
1158                         GXMAP(type,XK_KP_Home,          GHOST_kKeyNumpad7);
1159                         GXMAP(type,XK_KP_Up,            GHOST_kKeyNumpad8);
1160                         GXMAP(type,XK_KP_Page_Up,       GHOST_kKeyNumpad9);
1161                         GXMAP(type,XK_KP_Delete,        GHOST_kKeyNumpadPeriod);
1162
1163                         GXMAP(type,XK_KP_Enter,         GHOST_kKeyNumpadEnter);
1164                         GXMAP(type,XK_KP_Add,           GHOST_kKeyNumpadPlus);
1165                         GXMAP(type,XK_KP_Subtract,      GHOST_kKeyNumpadMinus);
1166                         GXMAP(type,XK_KP_Multiply,      GHOST_kKeyNumpadAsterisk);
1167                         GXMAP(type,XK_KP_Divide,        GHOST_kKeyNumpadSlash);
1168
1169                                 /* some extra sun cruft (NICE KEYBOARD!) */
1170 #ifdef __sun__
1171                         GXMAP(type,0xffde,                      GHOST_kKeyNumpad1);
1172                         GXMAP(type,0xffe0,                      GHOST_kKeyNumpad3);
1173                         GXMAP(type,0xffdc,                      GHOST_kKeyNumpad5);
1174                         GXMAP(type,0xffd8,                      GHOST_kKeyNumpad7);
1175                         GXMAP(type,0xffda,                      GHOST_kKeyNumpad9);
1176
1177                         GXMAP(type,0xffd6,                      GHOST_kKeyNumpadSlash);
1178                         GXMAP(type,0xffd7,                      GHOST_kKeyNumpadAsterisk);
1179 #endif
1180
1181                         default :
1182                                 type = GHOST_kKeyUnknown;
1183                                 break;
1184                 }
1185         }
1186
1187         return type;
1188 }
1189
1190 #undef GXMAP
1191
1192 /* from xclip.c xcout() v0.11 */
1193
1194 #define XCLIB_XCOUT_NONE                0 /* no context */
1195 #define XCLIB_XCOUT_SENTCONVSEL         1 /* sent a request */
1196 #define XCLIB_XCOUT_INCR                2 /* in an incr loop */
1197 #define XCLIB_XCOUT_FALLBACK            3 /* STRING failed, need fallback to UTF8 */
1198 #define XCLIB_XCOUT_FALLBACK_UTF8       4 /* UTF8 failed, move to compouned */
1199 #define XCLIB_XCOUT_FALLBACK_COMP       5 /* compouned failed, move to text. */
1200 #define XCLIB_XCOUT_FALLBACK_TEXT       6
1201
1202 // Retrieves the contents of a selections.
1203 void GHOST_SystemX11::getClipboard_xcout(XEvent evt,
1204         Atom sel, Atom target, unsigned char **txt,
1205         unsigned long *len, unsigned int *context) const
1206 {
1207         Atom pty_type;
1208         int pty_format;
1209         unsigned char *buffer;
1210         unsigned long pty_size, pty_items;
1211         unsigned char *ltxt= *txt;
1212
1213         vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();
1214         vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
1215         GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
1216         Window win = window->getXWindow();
1217
1218         switch (*context) {
1219                 // There is no context, do an XConvertSelection()
1220                 case XCLIB_XCOUT_NONE:
1221                         // Initialise return length to 0
1222                         if (*len > 0) {
1223                                 free(*txt);
1224                                 *len = 0;
1225                         }
1226
1227                         // Send a selection request
1228                         XConvertSelection(m_display, sel, target, m_xclip_out, win, CurrentTime);
1229                         *context = XCLIB_XCOUT_SENTCONVSEL;
1230                         return;
1231
1232                 case XCLIB_XCOUT_SENTCONVSEL:
1233                         if (evt.type != SelectionNotify)
1234                                 return;
1235
1236                         if (target == m_utf8_string && evt.xselection.property == None) {
1237                                 *context= XCLIB_XCOUT_FALLBACK_UTF8;
1238                                 return;
1239                         }
1240                         else if (target == m_compound_text && evt.xselection.property == None) {
1241                                 *context= XCLIB_XCOUT_FALLBACK_COMP;
1242                                 return;
1243                         }
1244                         else if (target == m_text && evt.xselection.property == None) {
1245                                 *context= XCLIB_XCOUT_FALLBACK_TEXT;
1246                                 return;
1247                         }
1248
1249                         // find the size and format of the data in property
1250                         XGetWindowProperty(m_display, win, m_xclip_out, 0, 0, False,
1251                                 AnyPropertyType, &pty_type, &pty_format,
1252                                 &pty_items, &pty_size, &buffer);
1253                         XFree(buffer);
1254
1255                         if (pty_type == m_incr) {
1256                                 // start INCR mechanism by deleting property
1257                                 XDeleteProperty(m_display, win, m_xclip_out);
1258                                 XFlush(m_display);
1259                                 *context = XCLIB_XCOUT_INCR;
1260                                 return;
1261                         }
1262
1263                         // if it's not incr, and not format == 8, then there's
1264                         // nothing in the selection (that xclip understands, anyway)
1265
1266                         if (pty_format != 8) {
1267                                 *context = XCLIB_XCOUT_NONE;
1268                                 return;
1269                         }
1270
1271                         // not using INCR mechanism, just read the property
1272                         XGetWindowProperty(m_display, win, m_xclip_out, 0, (long) pty_size,
1273                                         False, AnyPropertyType, &pty_type,
1274                                         &pty_format, &pty_items, &pty_size, &buffer);
1275
1276                         // finished with property, delete it
1277                         XDeleteProperty(m_display, win, m_xclip_out);
1278
1279                         // copy the buffer to the pointer for returned data
1280                         ltxt = (unsigned char *) malloc(pty_items);
1281                         memcpy(ltxt, buffer, pty_items);
1282
1283                         // set the length of the returned data
1284                         *len = pty_items;
1285                         *txt = ltxt;
1286
1287                         // free the buffer
1288                         XFree(buffer);
1289
1290                         *context = XCLIB_XCOUT_NONE;
1291
1292                         // complete contents of selection fetched, return 1
1293                         return;
1294
1295                 case XCLIB_XCOUT_INCR:
1296                         // To use the INCR method, we basically delete the
1297                         // property with the selection in it, wait for an
1298                         // event indicating that the property has been created,
1299                         // then read it, delete it, etc.
1300
1301                         // make sure that the event is relevant
1302                         if (evt.type != PropertyNotify)
1303                                 return;
1304
1305                         // skip unless the property has a new value
1306                         if (evt.xproperty.state != PropertyNewValue)
1307                                 return;
1308
1309                         // check size and format of the property
1310                         XGetWindowProperty(m_display, win, m_xclip_out, 0, 0, False,
1311                                 AnyPropertyType, &pty_type, &pty_format,
1312                                 &pty_items, &pty_size, (unsigned char **) &buffer);
1313
1314                         if (pty_format != 8) {
1315                                 // property does not contain text, delete it
1316                                 // to tell the other X client that we have read 
1317                                 // it and to send the next property
1318                                 XFree(buffer);
1319                                 XDeleteProperty(m_display, win, m_xclip_out);
1320                                 return;
1321                         }
1322
1323                         if (pty_size == 0) {
1324                                 // no more data, exit from loop
1325                                 XFree(buffer);
1326                                 XDeleteProperty(m_display, win, m_xclip_out);
1327                                 *context = XCLIB_XCOUT_NONE;
1328
1329                                 // this means that an INCR transfer is now
1330                                 // complete, return 1
1331                                 return;
1332                         }
1333
1334                         XFree(buffer);
1335
1336                         // if we have come this far, the propery contains
1337                         // text, we know the size.
1338                         XGetWindowProperty(m_display, win, m_xclip_out, 0, (long) pty_size,
1339                                 False, AnyPropertyType, &pty_type, &pty_format,
1340                                 &pty_items, &pty_size, (unsigned char **) &buffer);
1341
1342                         // allocate memory to accommodate data in *txt
1343                         if (*len == 0) {
1344                                 *len = pty_items;
1345                                 ltxt = (unsigned char *) malloc(*len);
1346                         }
1347                         else {
1348                                 *len += pty_items;
1349                                 ltxt = (unsigned char *) realloc(ltxt, *len);
1350                         }
1351
1352                         // add data to ltxt
1353                         memcpy(&ltxt[*len - pty_items], buffer, pty_items);
1354
1355                         *txt = ltxt;
1356                         XFree(buffer);
1357
1358                         // delete property to get the next item
1359                         XDeleteProperty(m_display, win, m_xclip_out);
1360                         XFlush(m_display);
1361                         return;
1362         }
1363         return;
1364 }
1365
1366 GHOST_TUns8 *GHOST_SystemX11::getClipboard(bool selection) const
1367 {
1368         Atom sseln;
1369         Atom target= m_string;
1370         Window owner;
1371
1372         // from xclip.c doOut() v0.11
1373         unsigned char *sel_buf;
1374         unsigned long sel_len= 0;
1375         XEvent evt;
1376         unsigned int context= XCLIB_XCOUT_NONE;
1377
1378         if (selection == True)
1379                 sseln= m_primary;
1380         else
1381                 sseln= m_clipboard;
1382
1383         vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();
1384         vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
1385         GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
1386         Window win = window->getXWindow();
1387
1388         /* check if we are the owner. */
1389         owner= XGetSelectionOwner(m_display, sseln);
1390         if (owner == win) {
1391                 if (sseln == m_clipboard) {
1392                         sel_buf= (unsigned char *)malloc(strlen(txt_cut_buffer)+1);
1393                         strcpy((char *)sel_buf, txt_cut_buffer);
1394                         return((GHOST_TUns8*)sel_buf);
1395                 }
1396                 else {
1397                         sel_buf= (unsigned char *)malloc(strlen(txt_select_buffer)+1);
1398                         strcpy((char *)sel_buf, txt_select_buffer);
1399                         return((GHOST_TUns8*)sel_buf);
1400                 }
1401         }
1402         else if (owner == None)
1403                 return(NULL);
1404
1405         while (1) {
1406                 /* only get an event if xcout() is doing something */
1407                 if (context != XCLIB_XCOUT_NONE)
1408                         XNextEvent(m_display, &evt);
1409
1410                 /* fetch the selection, or part of it */
1411                 getClipboard_xcout(evt, sseln, target, &sel_buf, &sel_len, &context);
1412
1413                 /* fallback is needed. set XA_STRING to target and restart the loop. */
1414                 if (context == XCLIB_XCOUT_FALLBACK) {
1415                         context= XCLIB_XCOUT_NONE;
1416                         target= m_string;
1417                         continue;
1418                 }
1419                 else if (context == XCLIB_XCOUT_FALLBACK_UTF8) {
1420                         /* utf8 fail, move to compouned text. */
1421                         context= XCLIB_XCOUT_NONE;
1422                         target= m_compound_text;
1423                         continue;
1424                 }
1425                 else if (context == XCLIB_XCOUT_FALLBACK_COMP) {
1426                         /* compouned text faile, move to text. */
1427                         context= XCLIB_XCOUT_NONE;
1428                         target= m_text;
1429                         continue;
1430                 }
1431
1432                 /* only continue if xcout() is doing something */
1433                 if (context == XCLIB_XCOUT_NONE)
1434                         break;
1435         }
1436
1437         if (sel_len) {
1438                 /* only print the buffer out, and free it, if it's not
1439                  * empty
1440                  */
1441                 unsigned char *tmp_data = (unsigned char*) malloc(sel_len+1);
1442                 memcpy((char*)tmp_data, (char*)sel_buf, sel_len);
1443                 tmp_data[sel_len] = '\0';
1444                 
1445                 if (sseln == m_string)
1446                         XFree(sel_buf);
1447                 else
1448                         free(sel_buf);
1449                 
1450                 return (GHOST_TUns8*)tmp_data;
1451         }
1452         return(NULL);
1453 }
1454
1455 void GHOST_SystemX11::putClipboard(GHOST_TInt8 *buffer, bool selection) const
1456 {
1457         Window m_window, owner;
1458
1459         vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();      
1460         vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
1461         GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
1462         m_window = window->getXWindow();
1463
1464         if (buffer) {
1465                 if (selection == False) {
1466                         XSetSelectionOwner(m_display, m_clipboard, m_window, CurrentTime);
1467                         owner= XGetSelectionOwner(m_display, m_clipboard);
1468                         if (txt_cut_buffer)
1469                                 free((void*)txt_cut_buffer);
1470
1471                         txt_cut_buffer = (char*) malloc(strlen(buffer)+1);
1472                         strcpy(txt_cut_buffer, buffer);
1473                 } else {
1474                         XSetSelectionOwner(m_display, m_primary, m_window, CurrentTime);
1475                         owner= XGetSelectionOwner(m_display, m_primary);
1476                         if (txt_select_buffer)
1477                                 free((void*)txt_select_buffer);
1478
1479                         txt_select_buffer = (char*) malloc(strlen(buffer)+1);
1480                         strcpy(txt_select_buffer, buffer);
1481                 }
1482         
1483                 if (owner != m_window)
1484                         fprintf(stderr, "failed to own primary\n");
1485         }
1486 }
1487
1488 const GHOST_TUns8* GHOST_SystemX11::getSystemDir() const
1489 {
1490         return (GHOST_TUns8*) PREFIX "/share";
1491 }
1492
1493 const GHOST_TUns8* GHOST_SystemX11::getUserDir() const
1494 {
1495         char* env = getenv("HOME");
1496         if(env) {
1497                 return (GHOST_TUns8*) env;
1498         } else {
1499                 return NULL;
1500         }
1501 }
1502
1503 const GHOST_TUns8* GHOST_SystemX11::getBinaryDir() const
1504 {
1505         return NULL;
1506 }
1507