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