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