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