2d8d90c6c83d57d928e63efc0612a706b17c7f73
[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 KeyCode shift_l = XKeysymToKeycode(m_display,XK_Shift_L);
863         const KeyCode shift_r = XKeysymToKeycode(m_display,XK_Shift_R);
864         const KeyCode control_l = XKeysymToKeycode(m_display,XK_Control_L);
865         const KeyCode control_r = XKeysymToKeycode(m_display,XK_Control_R);
866         const KeyCode alt_l = XKeysymToKeycode(m_display,XK_Alt_L);
867         const KeyCode alt_r = XKeysymToKeycode(m_display,XK_Alt_R);
868         const KeyCode super_l = XKeysymToKeycode(m_display,XK_Super_L);
869         const KeyCode super_r = XKeysymToKeycode(m_display,XK_Super_R);
870
871         // Shift
872         if ((m_keyboard_vector[shift_l >> 3] >> (shift_l & 7)) & 1) {
873                 keys.set(GHOST_kModifierKeyLeftShift,true);
874         } else {
875                 keys.set(GHOST_kModifierKeyLeftShift,false);
876         }
877         if ((m_keyboard_vector[shift_r >> 3] >> (shift_r & 7)) & 1) {
878
879                 keys.set(GHOST_kModifierKeyRightShift,true);
880         } else {
881                 keys.set(GHOST_kModifierKeyRightShift,false);
882         }
883
884         // control (weep)
885         if ((m_keyboard_vector[control_l >> 3] >> (control_l & 7)) & 1) {
886                 keys.set(GHOST_kModifierKeyLeftControl,true);
887         } else {
888                 keys.set(GHOST_kModifierKeyLeftControl,false);
889         }
890         if ((m_keyboard_vector[control_r >> 3] >> (control_r & 7)) & 1) {
891                 keys.set(GHOST_kModifierKeyRightControl,true);
892         } else {
893                 keys.set(GHOST_kModifierKeyRightControl,false);
894         }
895
896         // Alt (yawn)
897         if ((m_keyboard_vector[alt_l >> 3] >> (alt_l & 7)) & 1) {
898                 keys.set(GHOST_kModifierKeyLeftAlt,true);
899         } else {
900                 keys.set(GHOST_kModifierKeyLeftAlt,false);
901         }       
902         if ((m_keyboard_vector[alt_r >> 3] >> (alt_r & 7)) & 1) {
903                 keys.set(GHOST_kModifierKeyRightAlt,true);
904         } else {
905                 keys.set(GHOST_kModifierKeyRightAlt,false);
906         }
907
908         // Super (Windows) - only one GHOST-kModifierKeyOS, so mapping
909         // to either
910         if ( ((m_keyboard_vector[super_l >> 3] >> (super_l & 7)) & 1) || 
911              ((m_keyboard_vector[super_r >> 3] >> (super_r & 7)) & 1) ) {
912                 keys.set(GHOST_kModifierKeyOS,true);
913         } else {
914                 keys.set(GHOST_kModifierKeyOS,false);
915         }
916         return GHOST_kSuccess;
917 }
918
919         GHOST_TSuccess 
920 GHOST_SystemX11::
921 getButtons(
922         GHOST_Buttons& buttons
923 ) const {
924
925         Window root_return, child_return;
926         int rx,ry,wx,wy;
927         unsigned int mask_return;
928
929         if (XQueryPointer(m_display,
930                           RootWindow(m_display,DefaultScreen(m_display)),
931                           &root_return,
932                           &child_return,
933                           &rx,&ry,
934                           &wx,&wy,
935                           &mask_return) == True)
936         {
937                 buttons.set(GHOST_kButtonMaskLeft,   (mask_return & Button1Mask) != 0);
938                 buttons.set(GHOST_kButtonMaskMiddle, (mask_return & Button2Mask) != 0);
939                 buttons.set(GHOST_kButtonMaskRight,  (mask_return & Button3Mask) != 0);
940         }
941         else {
942                 return GHOST_kFailure;
943         }       
944
945         return GHOST_kSuccess;
946 }
947
948
949         GHOST_TSuccess 
950 GHOST_SystemX11::
951 getCursorPosition(
952         GHOST_TInt32& x,
953         GHOST_TInt32& y
954 ) const {
955
956         Window root_return, child_return;
957         int rx,ry,wx,wy;
958         unsigned int mask_return;
959
960         if (XQueryPointer(
961                 m_display,
962                 RootWindow(m_display,DefaultScreen(m_display)),
963                 &root_return,
964                 &child_return,
965                 &rx,&ry,
966                 &wx,&wy,
967                 &mask_return
968         ) == False) {
969                 return GHOST_kFailure;
970         } else {
971                 x = rx;
972                 y = ry;
973         }       
974         return GHOST_kSuccess;
975 }
976
977
978         GHOST_TSuccess 
979 GHOST_SystemX11::
980 setCursorPosition(
981         GHOST_TInt32 x,
982         GHOST_TInt32 y
983 ) {
984
985         // This is a brute force move in screen coordinates
986         // XWarpPointer does relative moves so first determine the
987         // current pointer position.
988
989         int cx,cy;
990         if (getCursorPosition(cx,cy) == GHOST_kFailure) {
991                 return GHOST_kFailure;
992         }
993
994         int relx = x-cx;
995         int rely = y-cy;
996
997         XWarpPointer(m_display,None,None,0,0,0,0,relx,rely);
998         XSync(m_display, 0); /* Sync to process all requests */
999         
1000         return GHOST_kSuccess;
1001 }
1002
1003
1004         void
1005 GHOST_SystemX11::
1006 addDirtyWindow(
1007         GHOST_WindowX11 * bad_wind
1008 ){
1009
1010         GHOST_ASSERT((bad_wind != NULL), "addDirtyWindow() NULL ptr trapped (window)");
1011         
1012         m_dirty_windows.push_back(bad_wind);
1013 }
1014
1015
1016         bool
1017 GHOST_SystemX11::
1018 generateWindowExposeEvents(
1019 ){
1020
1021         vector<GHOST_WindowX11 *>::iterator w_start = m_dirty_windows.begin();
1022         vector<GHOST_WindowX11 *>::const_iterator w_end = m_dirty_windows.end();
1023         bool anyProcessed = false;
1024         
1025         for (;w_start != w_end; ++w_start) {
1026                 GHOST_Event * g_event = new 
1027                         GHOST_Event(
1028                                 getMilliSeconds(),
1029                                 GHOST_kEventWindowUpdate,
1030                                 *w_start
1031                         );                      
1032
1033                 (*w_start)->validate(); 
1034                 
1035                 if (g_event) {
1036                         pushEvent(g_event);
1037                         anyProcessed = true;
1038                 }
1039         }
1040
1041         m_dirty_windows.clear();
1042         return anyProcessed;
1043 }
1044
1045 #define GXMAP(k,x,y) case x: k = y; break; 
1046
1047 static GHOST_TKey
1048 convertXKey(KeySym key)
1049 {
1050         GHOST_TKey type;
1051
1052         if ((key >= XK_A) && (key <= XK_Z)) {
1053                 type = GHOST_TKey( key - XK_A + int(GHOST_kKeyA));
1054         } else if ((key >= XK_a) && (key <= XK_z)) {
1055                 type = GHOST_TKey(key - XK_a + int(GHOST_kKeyA));
1056         } else if ((key >= XK_0) && (key <= XK_9)) {
1057                 type = GHOST_TKey(key - XK_0 + int(GHOST_kKey0));
1058         } else if ((key >= XK_F1) && (key <= XK_F24)) {
1059                 type = GHOST_TKey(key - XK_F1 + int(GHOST_kKeyF1));
1060 #if defined(__sun) || defined(__sun__) 
1061                 /* This is a bit of a hack, but it looks like sun
1062                    Used F11 and friends for its special keys Stop,again etc..
1063                    So this little patch enables F11 and F12 to work as expected
1064                    following link has documentation on it: 
1065                    http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4734408
1066                    also from /usr/include/X11/Sunkeysym.h 
1067 #define SunXK_F36               0x1005FF10      // Labeled F11
1068 #define SunXK_F37               0x1005FF11      // Labeled F12 
1069
1070                                 mein@cs.umn.edu
1071                  */
1072                 
1073         } else if (key == 268828432) {
1074                 type = GHOST_kKeyF11;
1075         } else if (key == 268828433) {
1076                 type = GHOST_kKeyF12;
1077 #endif
1078         } else {
1079                 switch(key) {
1080                         GXMAP(type,XK_BackSpace,        GHOST_kKeyBackSpace);
1081                         GXMAP(type,XK_Tab,              GHOST_kKeyTab);
1082                         GXMAP(type,XK_Return,           GHOST_kKeyEnter);
1083                         GXMAP(type,XK_Escape,           GHOST_kKeyEsc);
1084                         GXMAP(type,XK_space,            GHOST_kKeySpace);
1085                         
1086                         GXMAP(type,XK_Linefeed,         GHOST_kKeyLinefeed);
1087                         GXMAP(type,XK_semicolon,        GHOST_kKeySemicolon);
1088                         GXMAP(type,XK_period,           GHOST_kKeyPeriod);
1089                         GXMAP(type,XK_comma,            GHOST_kKeyComma);
1090                         GXMAP(type,XK_quoteright,       GHOST_kKeyQuote);
1091                         GXMAP(type,XK_quoteleft,        GHOST_kKeyAccentGrave);
1092                         GXMAP(type,XK_minus,            GHOST_kKeyMinus);
1093                         GXMAP(type,XK_slash,            GHOST_kKeySlash);
1094                         GXMAP(type,XK_backslash,        GHOST_kKeyBackslash);
1095                         GXMAP(type,XK_equal,            GHOST_kKeyEqual);
1096                         GXMAP(type,XK_bracketleft,      GHOST_kKeyLeftBracket);
1097                         GXMAP(type,XK_bracketright,     GHOST_kKeyRightBracket);
1098                         GXMAP(type,XK_Pause,            GHOST_kKeyPause);
1099                         
1100                         GXMAP(type,XK_Shift_L,          GHOST_kKeyLeftShift);
1101                         GXMAP(type,XK_Shift_R,          GHOST_kKeyRightShift);
1102                         GXMAP(type,XK_Control_L,        GHOST_kKeyLeftControl);
1103                         GXMAP(type,XK_Control_R,        GHOST_kKeyRightControl);
1104                         GXMAP(type,XK_Alt_L,            GHOST_kKeyLeftAlt);
1105                         GXMAP(type,XK_Alt_R,            GHOST_kKeyRightAlt);
1106                         GXMAP(type,XK_Super_L,          GHOST_kKeyOS);
1107                         GXMAP(type,XK_Super_R,          GHOST_kKeyOS);
1108
1109                         GXMAP(type,XK_Insert,           GHOST_kKeyInsert);
1110                         GXMAP(type,XK_Delete,           GHOST_kKeyDelete);
1111                         GXMAP(type,XK_Home,                     GHOST_kKeyHome);
1112                         GXMAP(type,XK_End,                      GHOST_kKeyEnd);
1113                         GXMAP(type,XK_Page_Up,          GHOST_kKeyUpPage);
1114                         GXMAP(type,XK_Page_Down,        GHOST_kKeyDownPage);
1115
1116                         GXMAP(type,XK_Left,                     GHOST_kKeyLeftArrow);
1117                         GXMAP(type,XK_Right,            GHOST_kKeyRightArrow);
1118                         GXMAP(type,XK_Up,                       GHOST_kKeyUpArrow);
1119                         GXMAP(type,XK_Down,                     GHOST_kKeyDownArrow);
1120
1121                         GXMAP(type,XK_Caps_Lock,        GHOST_kKeyCapsLock);
1122                         GXMAP(type,XK_Scroll_Lock,      GHOST_kKeyScrollLock);
1123                         GXMAP(type,XK_Num_Lock,         GHOST_kKeyNumLock);
1124                         
1125                                 /* keypad events */
1126                                 
1127                         GXMAP(type,XK_KP_0,                     GHOST_kKeyNumpad0);
1128                         GXMAP(type,XK_KP_1,                     GHOST_kKeyNumpad1);
1129                         GXMAP(type,XK_KP_2,                     GHOST_kKeyNumpad2);
1130                         GXMAP(type,XK_KP_3,                     GHOST_kKeyNumpad3);
1131                         GXMAP(type,XK_KP_4,                     GHOST_kKeyNumpad4);
1132                         GXMAP(type,XK_KP_5,                     GHOST_kKeyNumpad5);
1133                         GXMAP(type,XK_KP_6,                     GHOST_kKeyNumpad6);
1134                         GXMAP(type,XK_KP_7,                     GHOST_kKeyNumpad7);
1135                         GXMAP(type,XK_KP_8,                     GHOST_kKeyNumpad8);
1136                         GXMAP(type,XK_KP_9,                     GHOST_kKeyNumpad9);
1137                         GXMAP(type,XK_KP_Decimal,       GHOST_kKeyNumpadPeriod);
1138
1139                         GXMAP(type,XK_KP_Insert,        GHOST_kKeyNumpad0);
1140                         GXMAP(type,XK_KP_End,           GHOST_kKeyNumpad1);
1141                         GXMAP(type,XK_KP_Down,          GHOST_kKeyNumpad2);
1142                         GXMAP(type,XK_KP_Page_Down,     GHOST_kKeyNumpad3);
1143                         GXMAP(type,XK_KP_Left,          GHOST_kKeyNumpad4);
1144                         GXMAP(type,XK_KP_Begin,         GHOST_kKeyNumpad5);
1145                         GXMAP(type,XK_KP_Right,         GHOST_kKeyNumpad6);
1146                         GXMAP(type,XK_KP_Home,          GHOST_kKeyNumpad7);
1147                         GXMAP(type,XK_KP_Up,            GHOST_kKeyNumpad8);
1148                         GXMAP(type,XK_KP_Page_Up,       GHOST_kKeyNumpad9);
1149                         GXMAP(type,XK_KP_Delete,        GHOST_kKeyNumpadPeriod);
1150
1151                         GXMAP(type,XK_KP_Enter,         GHOST_kKeyNumpadEnter);
1152                         GXMAP(type,XK_KP_Add,           GHOST_kKeyNumpadPlus);
1153                         GXMAP(type,XK_KP_Subtract,      GHOST_kKeyNumpadMinus);
1154                         GXMAP(type,XK_KP_Multiply,      GHOST_kKeyNumpadAsterisk);
1155                         GXMAP(type,XK_KP_Divide,        GHOST_kKeyNumpadSlash);
1156
1157                         /* Media keys in some keyboards and laptops with XFree86/Xorg */
1158 #ifdef WITH_XF86KEYSYM
1159                         GXMAP(type,XF86XK_AudioPlay,    GHOST_kKeyMediaPlay);
1160                         GXMAP(type,XF86XK_AudioStop,    GHOST_kKeyMediaStop);
1161                         GXMAP(type,XF86XK_AudioPrev,    GHOST_kKeyMediaFirst);
1162                         GXMAP(type,XF86XK_AudioRewind,  GHOST_kKeyMediaFirst);
1163                         GXMAP(type,XF86XK_AudioNext,    GHOST_kKeyMediaLast);
1164 #ifdef XF86XK_AudioForward /* Debian lenny's XF86keysym.h has no XF86XK_AudioForward define */
1165                         GXMAP(type,XF86XK_AudioForward, GHOST_kKeyMediaLast);
1166 #endif
1167 #endif
1168
1169                                 /* some extra sun cruft (NICE KEYBOARD!) */
1170 #ifdef __sun__
1171                         GXMAP(type,0xffde,                      GHOST_kKeyNumpad1);
1172                         GXMAP(type,0xffe0,                      GHOST_kKeyNumpad3);
1173                         GXMAP(type,0xffdc,                      GHOST_kKeyNumpad5);
1174                         GXMAP(type,0xffd8,                      GHOST_kKeyNumpad7);
1175                         GXMAP(type,0xffda,                      GHOST_kKeyNumpad9);
1176
1177                         GXMAP(type,0xffd6,                      GHOST_kKeyNumpadSlash);
1178                         GXMAP(type,0xffd7,                      GHOST_kKeyNumpadAsterisk);
1179 #endif
1180
1181                         default :
1182                                 type = GHOST_kKeyUnknown;
1183                                 break;
1184                 }
1185         }
1186
1187         return type;
1188 }
1189
1190 #undef GXMAP
1191
1192 /* from xclip.c xcout() v0.11 */
1193
1194 #define XCLIB_XCOUT_NONE                0 /* no context */
1195 #define XCLIB_XCOUT_SENTCONVSEL         1 /* sent a request */
1196 #define XCLIB_XCOUT_INCR                2 /* in an incr loop */
1197 #define XCLIB_XCOUT_FALLBACK            3 /* STRING failed, need fallback to UTF8 */
1198 #define XCLIB_XCOUT_FALLBACK_UTF8       4 /* UTF8 failed, move to compouned */
1199 #define XCLIB_XCOUT_FALLBACK_COMP       5 /* compouned failed, move to text. */
1200 #define XCLIB_XCOUT_FALLBACK_TEXT       6
1201
1202 // Retrieves the contents of a selections.
1203 void GHOST_SystemX11::getClipboard_xcout(XEvent evt,
1204         Atom sel, Atom target, unsigned char **txt,
1205         unsigned long *len, unsigned int *context) const
1206 {
1207         Atom pty_type;
1208         int pty_format;
1209         unsigned char *buffer;
1210         unsigned long pty_size, pty_items;
1211         unsigned char *ltxt= *txt;
1212
1213         vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();
1214         vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
1215         GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
1216         Window win = window->getXWindow();
1217
1218         switch (*context) {
1219                 // There is no context, do an XConvertSelection()
1220                 case XCLIB_XCOUT_NONE:
1221                         // Initialise return length to 0
1222                         if (*len > 0) {
1223                                 free(*txt);
1224                                 *len = 0;
1225                         }
1226
1227                         // Send a selection request
1228                         XConvertSelection(m_display, sel, target, m_xclip_out, win, CurrentTime);
1229                         *context = XCLIB_XCOUT_SENTCONVSEL;
1230                         return;
1231
1232                 case XCLIB_XCOUT_SENTCONVSEL:
1233                         if (evt.type != SelectionNotify)
1234                                 return;
1235
1236                         if (target == m_utf8_string && evt.xselection.property == None) {
1237                                 *context= XCLIB_XCOUT_FALLBACK_UTF8;
1238                                 return;
1239                         }
1240                         else if (target == m_compound_text && evt.xselection.property == None) {
1241                                 *context= XCLIB_XCOUT_FALLBACK_COMP;
1242                                 return;
1243                         }
1244                         else if (target == m_text && evt.xselection.property == None) {
1245                                 *context= XCLIB_XCOUT_FALLBACK_TEXT;
1246                                 return;
1247                         }
1248
1249                         // find the size and format of the data in property
1250                         XGetWindowProperty(m_display, win, m_xclip_out, 0, 0, False,
1251                                 AnyPropertyType, &pty_type, &pty_format,
1252                                 &pty_items, &pty_size, &buffer);
1253                         XFree(buffer);
1254
1255                         if (pty_type == m_incr) {
1256                                 // start INCR mechanism by deleting property
1257                                 XDeleteProperty(m_display, win, m_xclip_out);
1258                                 XFlush(m_display);
1259                                 *context = XCLIB_XCOUT_INCR;
1260                                 return;
1261                         }
1262
1263                         // if it's not incr, and not format == 8, then there's
1264                         // nothing in the selection (that xclip understands, anyway)
1265
1266                         if (pty_format != 8) {
1267                                 *context = XCLIB_XCOUT_NONE;
1268                                 return;
1269                         }
1270
1271                         // not using INCR mechanism, just read the property
1272                         XGetWindowProperty(m_display, win, m_xclip_out, 0, (long) pty_size,
1273                                         False, AnyPropertyType, &pty_type,
1274                                         &pty_format, &pty_items, &pty_size, &buffer);
1275
1276                         // finished with property, delete it
1277                         XDeleteProperty(m_display, win, m_xclip_out);
1278
1279                         // copy the buffer to the pointer for returned data
1280                         ltxt = (unsigned char *) malloc(pty_items);
1281                         memcpy(ltxt, buffer, pty_items);
1282
1283                         // set the length of the returned data
1284                         *len = pty_items;
1285                         *txt = ltxt;
1286
1287                         // free the buffer
1288                         XFree(buffer);
1289
1290                         *context = XCLIB_XCOUT_NONE;
1291
1292                         // complete contents of selection fetched, return 1
1293                         return;
1294
1295                 case XCLIB_XCOUT_INCR:
1296                         // To use the INCR method, we basically delete the
1297                         // property with the selection in it, wait for an
1298                         // event indicating that the property has been created,
1299                         // then read it, delete it, etc.
1300
1301                         // make sure that the event is relevant
1302                         if (evt.type != PropertyNotify)
1303                                 return;
1304
1305                         // skip unless the property has a new value
1306                         if (evt.xproperty.state != PropertyNewValue)
1307                                 return;
1308
1309                         // check size and format of the property
1310                         XGetWindowProperty(m_display, win, m_xclip_out, 0, 0, False,
1311                                 AnyPropertyType, &pty_type, &pty_format,
1312                                 &pty_items, &pty_size, (unsigned char **) &buffer);
1313
1314                         if (pty_format != 8) {
1315                                 // property does not contain text, delete it
1316                                 // to tell the other X client that we have read 
1317                                 // it and to send the next property
1318                                 XFree(buffer);
1319                                 XDeleteProperty(m_display, win, m_xclip_out);
1320                                 return;
1321                         }
1322
1323                         if (pty_size == 0) {
1324                                 // no more data, exit from loop
1325                                 XFree(buffer);
1326                                 XDeleteProperty(m_display, win, m_xclip_out);
1327                                 *context = XCLIB_XCOUT_NONE;
1328
1329                                 // this means that an INCR transfer is now
1330                                 // complete, return 1
1331                                 return;
1332                         }
1333
1334                         XFree(buffer);
1335
1336                         // if we have come this far, the propery contains
1337                         // text, we know the size.
1338                         XGetWindowProperty(m_display, win, m_xclip_out, 0, (long) pty_size,
1339                                 False, AnyPropertyType, &pty_type, &pty_format,
1340                                 &pty_items, &pty_size, (unsigned char **) &buffer);
1341
1342                         // allocate memory to accommodate data in *txt
1343                         if (*len == 0) {
1344                                 *len = pty_items;
1345                                 ltxt = (unsigned char *) malloc(*len);
1346                         }
1347                         else {
1348                                 *len += pty_items;
1349                                 ltxt = (unsigned char *) realloc(ltxt, *len);
1350                         }
1351
1352                         // add data to ltxt
1353                         memcpy(&ltxt[*len - pty_items], buffer, pty_items);
1354
1355                         *txt = ltxt;
1356                         XFree(buffer);
1357
1358                         // delete property to get the next item
1359                         XDeleteProperty(m_display, win, m_xclip_out);
1360                         XFlush(m_display);
1361                         return;
1362         }
1363         return;
1364 }
1365
1366 GHOST_TUns8 *GHOST_SystemX11::getClipboard(bool selection) const
1367 {
1368         Atom sseln;
1369         Atom target= m_string;
1370         Window owner;
1371
1372         // from xclip.c doOut() v0.11
1373         unsigned char *sel_buf;
1374         unsigned long sel_len= 0;
1375         XEvent evt;
1376         unsigned int context= XCLIB_XCOUT_NONE;
1377
1378         if (selection == True)
1379                 sseln= m_primary;
1380         else
1381                 sseln= m_clipboard;
1382
1383         vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();
1384         vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
1385         GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
1386         Window win = window->getXWindow();
1387
1388         /* check if we are the owner. */
1389         owner= XGetSelectionOwner(m_display, sseln);
1390         if (owner == win) {
1391                 if (sseln == m_clipboard) {
1392                         sel_buf= (unsigned char *)malloc(strlen(txt_cut_buffer)+1);
1393                         strcpy((char *)sel_buf, txt_cut_buffer);
1394                         return((GHOST_TUns8*)sel_buf);
1395                 }
1396                 else {
1397                         sel_buf= (unsigned char *)malloc(strlen(txt_select_buffer)+1);
1398                         strcpy((char *)sel_buf, txt_select_buffer);
1399                         return((GHOST_TUns8*)sel_buf);
1400                 }
1401         }
1402         else if (owner == None)
1403                 return(NULL);
1404
1405         while (1) {
1406                 /* only get an event if xcout() is doing something */
1407                 if (context != XCLIB_XCOUT_NONE)
1408                         XNextEvent(m_display, &evt);
1409
1410                 /* fetch the selection, or part of it */
1411                 getClipboard_xcout(evt, sseln, target, &sel_buf, &sel_len, &context);
1412
1413                 /* fallback is needed. set XA_STRING to target and restart the loop. */
1414                 if (context == XCLIB_XCOUT_FALLBACK) {
1415                         context= XCLIB_XCOUT_NONE;
1416                         target= m_string;
1417                         continue;
1418                 }
1419                 else if (context == XCLIB_XCOUT_FALLBACK_UTF8) {
1420                         /* utf8 fail, move to compouned text. */
1421                         context= XCLIB_XCOUT_NONE;
1422                         target= m_compound_text;
1423                         continue;
1424                 }
1425                 else if (context == XCLIB_XCOUT_FALLBACK_COMP) {
1426                         /* compouned text faile, move to text. */
1427                         context= XCLIB_XCOUT_NONE;
1428                         target= m_text;
1429                         continue;
1430                 }
1431
1432                 /* only continue if xcout() is doing something */
1433                 if (context == XCLIB_XCOUT_NONE)
1434                         break;
1435         }
1436
1437         if (sel_len) {
1438                 /* only print the buffer out, and free it, if it's not
1439                  * empty
1440                  */
1441                 unsigned char *tmp_data = (unsigned char*) malloc(sel_len+1);
1442                 memcpy((char*)tmp_data, (char*)sel_buf, sel_len);
1443                 tmp_data[sel_len] = '\0';
1444                 
1445                 if (sseln == m_string)
1446                         XFree(sel_buf);
1447                 else
1448                         free(sel_buf);
1449                 
1450                 return (GHOST_TUns8*)tmp_data;
1451         }
1452         return(NULL);
1453 }
1454
1455 void GHOST_SystemX11::putClipboard(GHOST_TInt8 *buffer, bool selection) const
1456 {
1457         Window m_window, owner;
1458
1459         vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();      
1460         vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
1461         GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
1462         m_window = window->getXWindow();
1463
1464         if (buffer) {
1465                 if (selection == False) {
1466                         XSetSelectionOwner(m_display, m_clipboard, m_window, CurrentTime);
1467                         owner= XGetSelectionOwner(m_display, m_clipboard);
1468                         if (txt_cut_buffer)
1469                                 free((void*)txt_cut_buffer);
1470
1471                         txt_cut_buffer = (char*) malloc(strlen(buffer)+1);
1472                         strcpy(txt_cut_buffer, buffer);
1473                 } else {
1474                         XSetSelectionOwner(m_display, m_primary, m_window, CurrentTime);
1475                         owner= XGetSelectionOwner(m_display, m_primary);
1476                         if (txt_select_buffer)
1477                                 free((void*)txt_select_buffer);
1478
1479                         txt_select_buffer = (char*) malloc(strlen(buffer)+1);
1480                         strcpy(txt_select_buffer, buffer);
1481                 }
1482
1483                 if (owner != m_window)
1484                         fprintf(stderr, "failed to own primary\n");
1485         }
1486 }