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