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