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