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