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