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