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