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