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