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