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