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