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