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