d701f9264b8be36d076952766c784203ccc829e0
[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, string, compound_text, c_string;
771                         XSelectionRequestEvent *xse = &xe->xselectionrequest;
772                         
773                         target = XInternAtom(m_display, "TARGETS", False);
774                         string = XInternAtom(m_display, "STRING", False);
775                         compound_text = XInternAtom(m_display, "COMPOUND_TEXT", False);
776                         c_string = XInternAtom(m_display, "C_STRING", False);
777                         
778                         /* support obsolete clients */
779                         if (xse->property == None) {
780                                 xse->property = xse->target;
781                         }
782                         
783                         nxe.xselection.type = SelectionNotify;
784                         nxe.xselection.requestor = xse->requestor;
785                         nxe.xselection.property = xse->property;
786                         nxe.xselection.display = xse->display;
787                         nxe.xselection.selection = xse->selection;
788                         nxe.xselection.target = xse->target;
789                         nxe.xselection.time = xse->time;
790                         
791                         /*Check to see if the requestor is asking for String*/
792                         if(xse->target == string || xse->target == compound_text || xse->target == c_string) {
793                                 if (xse->selection == XInternAtom(m_display, "PRIMARY", False)) {
794                                         XChangeProperty(m_display, xse->requestor, xse->property, xse->target, 8, PropModeReplace,
795                                                         (unsigned char*)txt_select_buffer, strlen(txt_select_buffer));
796                                 } else if (xse->selection == XInternAtom(m_display, "CLIPBOARD", False)) {
797                                         XChangeProperty(m_display, xse->requestor, xse->property, xse->target, 8, PropModeReplace,
798                                                         (unsigned char*)txt_cut_buffer, strlen(txt_cut_buffer));
799                                 }
800                         } else if (xse->target == target) {
801                                 Atom alist[4];
802                                 alist[0] = target;
803                                 alist[1] = string;
804                                 alist[2] = compound_text;
805                                 alist[3] = c_string;
806                                 XChangeProperty(m_display, xse->requestor, xse->property, xse->target, 32, PropModeReplace,
807                                                 (unsigned char*)alist, 4);
808                                 XFlush(m_display);
809                         } else  {
810                                 //Change property to None because we do not support anything but STRING
811                                 nxe.xselection.property = None;
812                         }
813                         
814                         //Send the event to the client 0 0 == False, SelectionNotify
815                         XSendEvent(m_display, xse->requestor, 0, 0, &nxe);
816                         XFlush(m_display);
817                         break;
818                 }
819                 
820                 default: {
821 #ifdef WITH_X11_XINPUT
822                         if(xe->type == window->GetXTablet().MotionEvent) 
823                         {
824                                 XDeviceMotionEvent* data = (XDeviceMotionEvent*)xe;
825                                 window->GetXTablet().CommonData.Pressure= 
826                                         data->axis_data[2]/((float)window->GetXTablet().PressureLevels);
827                         
828                         /* the (short) cast and the &0xffff is bizarre and unexplained anywhere,
829                          * but I got garbage data without it. Found it in the xidump.c source --matt */
830                                 window->GetXTablet().CommonData.Xtilt= 
831                                         (short)(data->axis_data[3]&0xffff)/((float)window->GetXTablet().XtiltLevels);
832                                 window->GetXTablet().CommonData.Ytilt= 
833                                         (short)(data->axis_data[4]&0xffff)/((float)window->GetXTablet().YtiltLevels);
834                         }
835                         else if(xe->type == window->GetXTablet().ProxInEvent) 
836                         {
837                                 XProximityNotifyEvent* data = (XProximityNotifyEvent*)xe;
838                                 if(data->deviceid == window->GetXTablet().StylusID)
839                                         window->GetXTablet().CommonData.Active= GHOST_kTabletModeStylus;
840                                 else if(data->deviceid == window->GetXTablet().EraserID)
841                                         window->GetXTablet().CommonData.Active= GHOST_kTabletModeEraser;
842                         }
843                         else if(xe->type == window->GetXTablet().ProxOutEvent)
844                                 window->GetXTablet().CommonData.Active= GHOST_kTabletModeNone;
845 #endif // WITH_X11_XINPUT
846                         break;
847                 }
848         }
849
850         if (g_event) {
851                 pushEvent(g_event);
852         }
853 }
854
855         GHOST_TSuccess 
856 GHOST_SystemX11::
857 getModifierKeys(
858         GHOST_ModifierKeys& keys
859 ) const {
860
861         // analyse the masks retuned from XQueryPointer.
862
863         memset((void *)m_keyboard_vector,0,sizeof(m_keyboard_vector));
864
865         XQueryKeymap(m_display,(char *)m_keyboard_vector);
866
867         // now translate key symobols into keycodes and
868         // test with vector.
869
870         const static KeyCode shift_l = XKeysymToKeycode(m_display,XK_Shift_L);
871         const static KeyCode shift_r = XKeysymToKeycode(m_display,XK_Shift_R);
872         const static KeyCode control_l = XKeysymToKeycode(m_display,XK_Control_L);
873         const static KeyCode control_r = XKeysymToKeycode(m_display,XK_Control_R);
874         const static KeyCode alt_l = XKeysymToKeycode(m_display,XK_Alt_L);
875         const static KeyCode alt_r = XKeysymToKeycode(m_display,XK_Alt_R);
876         const static KeyCode super_l = XKeysymToKeycode(m_display,XK_Super_L);
877         const static KeyCode super_r = XKeysymToKeycode(m_display,XK_Super_R);
878
879         // shift
880         keys.set(GHOST_kModifierKeyLeftShift, ((m_keyboard_vector[shift_l >> 3] >> (shift_l & 7)) & 1) != 0);
881         keys.set(GHOST_kModifierKeyRightShift, ((m_keyboard_vector[shift_r >> 3] >> (shift_r & 7)) & 1) != 0);
882         // control
883         keys.set(GHOST_kModifierKeyLeftControl, ((m_keyboard_vector[control_l >> 3] >> (control_l & 7)) & 1) != 0);
884         keys.set(GHOST_kModifierKeyRightControl, ((m_keyboard_vector[control_r >> 3] >> (control_r & 7)) & 1) != 0);
885         // alt
886         keys.set(GHOST_kModifierKeyLeftAlt, ((m_keyboard_vector[alt_l >> 3] >> (alt_l & 7)) & 1) != 0);
887         keys.set(GHOST_kModifierKeyRightAlt, ((m_keyboard_vector[alt_r >> 3] >> (alt_r & 7)) & 1) != 0);
888         // super (windows) - only one GHOST-kModifierKeyOS, so mapping to either
889         keys.set(GHOST_kModifierKeyOS, ( ((m_keyboard_vector[super_l >> 3] >> (super_l & 7)) & 1) ||
890                                          ((m_keyboard_vector[super_r >> 3] >> (super_r & 7)) & 1) ) != 0);
891
892         return GHOST_kSuccess;
893 }
894
895         GHOST_TSuccess 
896 GHOST_SystemX11::
897 getButtons(
898         GHOST_Buttons& buttons
899 ) const {
900
901         Window root_return, child_return;
902         int rx,ry,wx,wy;
903         unsigned int mask_return;
904
905         if (XQueryPointer(m_display,
906                           RootWindow(m_display,DefaultScreen(m_display)),
907                           &root_return,
908                           &child_return,
909                           &rx,&ry,
910                           &wx,&wy,
911                           &mask_return) == True)
912         {
913                 buttons.set(GHOST_kButtonMaskLeft,   (mask_return & Button1Mask) != 0);
914                 buttons.set(GHOST_kButtonMaskMiddle, (mask_return & Button2Mask) != 0);
915                 buttons.set(GHOST_kButtonMaskRight,  (mask_return & Button3Mask) != 0);
916         }
917         else {
918                 return GHOST_kFailure;
919         }       
920
921         return GHOST_kSuccess;
922 }
923
924
925         GHOST_TSuccess 
926 GHOST_SystemX11::
927 getCursorPosition(
928         GHOST_TInt32& x,
929         GHOST_TInt32& y
930 ) const {
931
932         Window root_return, child_return;
933         int rx,ry,wx,wy;
934         unsigned int mask_return;
935
936         if (XQueryPointer(
937                 m_display,
938                 RootWindow(m_display,DefaultScreen(m_display)),
939                 &root_return,
940                 &child_return,
941                 &rx,&ry,
942                 &wx,&wy,
943                 &mask_return
944         ) == False) {
945                 return GHOST_kFailure;
946         } else {
947                 x = rx;
948                 y = ry;
949         }       
950         return GHOST_kSuccess;
951 }
952
953
954         GHOST_TSuccess 
955 GHOST_SystemX11::
956 setCursorPosition(
957         GHOST_TInt32 x,
958         GHOST_TInt32 y
959 ) {
960
961         // This is a brute force move in screen coordinates
962         // XWarpPointer does relative moves so first determine the
963         // current pointer position.
964
965         int cx,cy;
966         if (getCursorPosition(cx,cy) == GHOST_kFailure) {
967                 return GHOST_kFailure;
968         }
969
970         int relx = x-cx;
971         int rely = y-cy;
972
973         XWarpPointer(m_display,None,None,0,0,0,0,relx,rely);
974         XSync(m_display, 0); /* Sync to process all requests */
975         
976         return GHOST_kSuccess;
977 }
978
979
980         void
981 GHOST_SystemX11::
982 addDirtyWindow(
983         GHOST_WindowX11 * bad_wind
984 ){
985
986         GHOST_ASSERT((bad_wind != NULL), "addDirtyWindow() NULL ptr trapped (window)");
987         
988         m_dirty_windows.push_back(bad_wind);
989 }
990
991
992         bool
993 GHOST_SystemX11::
994 generateWindowExposeEvents(
995 ){
996
997         vector<GHOST_WindowX11 *>::iterator w_start = m_dirty_windows.begin();
998         vector<GHOST_WindowX11 *>::const_iterator w_end = m_dirty_windows.end();
999         bool anyProcessed = false;
1000         
1001         for (;w_start != w_end; ++w_start) {
1002                 GHOST_Event * g_event = new 
1003                         GHOST_Event(
1004                                 getMilliSeconds(),
1005                                 GHOST_kEventWindowUpdate,
1006                                 *w_start
1007                         );                      
1008
1009                 (*w_start)->validate(); 
1010                 
1011                 if (g_event) {
1012                         pushEvent(g_event);
1013                         anyProcessed = true;
1014                 }
1015         }
1016
1017         m_dirty_windows.clear();
1018         return anyProcessed;
1019 }
1020
1021 #define GXMAP(k,x,y) case x: k = y; break; 
1022
1023 static GHOST_TKey
1024 convertXKey(KeySym key)
1025 {
1026         GHOST_TKey type;
1027
1028         if ((key >= XK_A) && (key <= XK_Z)) {
1029                 type = GHOST_TKey( key - XK_A + int(GHOST_kKeyA));
1030         } else if ((key >= XK_a) && (key <= XK_z)) {
1031                 type = GHOST_TKey(key - XK_a + int(GHOST_kKeyA));
1032         } else if ((key >= XK_0) && (key <= XK_9)) {
1033                 type = GHOST_TKey(key - XK_0 + int(GHOST_kKey0));
1034         } else if ((key >= XK_F1) && (key <= XK_F24)) {
1035                 type = GHOST_TKey(key - XK_F1 + int(GHOST_kKeyF1));
1036 #if defined(__sun) || defined(__sun__) 
1037                 /* This is a bit of a hack, but it looks like sun
1038                    Used F11 and friends for its special keys Stop,again etc..
1039                    So this little patch enables F11 and F12 to work as expected
1040                    following link has documentation on it: 
1041                    http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4734408
1042                    also from /usr/include/X11/Sunkeysym.h 
1043 #define SunXK_F36               0x1005FF10      // Labeled F11
1044 #define SunXK_F37               0x1005FF11      // Labeled F12 
1045
1046                                 mein@cs.umn.edu
1047                  */
1048                 
1049         } else if (key == 268828432) {
1050                 type = GHOST_kKeyF11;
1051         } else if (key == 268828433) {
1052                 type = GHOST_kKeyF12;
1053 #endif
1054         } else {
1055                 switch(key) {
1056                         GXMAP(type,XK_BackSpace,        GHOST_kKeyBackSpace);
1057                         GXMAP(type,XK_Tab,              GHOST_kKeyTab);
1058                         GXMAP(type,XK_Return,           GHOST_kKeyEnter);
1059                         GXMAP(type,XK_Escape,           GHOST_kKeyEsc);
1060                         GXMAP(type,XK_space,            GHOST_kKeySpace);
1061                         
1062                         GXMAP(type,XK_Linefeed,         GHOST_kKeyLinefeed);
1063                         GXMAP(type,XK_semicolon,        GHOST_kKeySemicolon);
1064                         GXMAP(type,XK_period,           GHOST_kKeyPeriod);
1065                         GXMAP(type,XK_comma,            GHOST_kKeyComma);
1066                         GXMAP(type,XK_quoteright,       GHOST_kKeyQuote);
1067                         GXMAP(type,XK_quoteleft,        GHOST_kKeyAccentGrave);
1068                         GXMAP(type,XK_minus,            GHOST_kKeyMinus);
1069                         GXMAP(type,XK_slash,            GHOST_kKeySlash);
1070                         GXMAP(type,XK_backslash,        GHOST_kKeyBackslash);
1071                         GXMAP(type,XK_equal,            GHOST_kKeyEqual);
1072                         GXMAP(type,XK_bracketleft,      GHOST_kKeyLeftBracket);
1073                         GXMAP(type,XK_bracketright,     GHOST_kKeyRightBracket);
1074                         GXMAP(type,XK_Pause,            GHOST_kKeyPause);
1075                         
1076                         GXMAP(type,XK_Shift_L,          GHOST_kKeyLeftShift);
1077                         GXMAP(type,XK_Shift_R,          GHOST_kKeyRightShift);
1078                         GXMAP(type,XK_Control_L,        GHOST_kKeyLeftControl);
1079                         GXMAP(type,XK_Control_R,        GHOST_kKeyRightControl);
1080                         GXMAP(type,XK_Alt_L,            GHOST_kKeyLeftAlt);
1081                         GXMAP(type,XK_Alt_R,            GHOST_kKeyRightAlt);
1082                         GXMAP(type,XK_Super_L,          GHOST_kKeyOS);
1083                         GXMAP(type,XK_Super_R,          GHOST_kKeyOS);
1084
1085                         GXMAP(type,XK_Insert,           GHOST_kKeyInsert);
1086                         GXMAP(type,XK_Delete,           GHOST_kKeyDelete);
1087                         GXMAP(type,XK_Home,                     GHOST_kKeyHome);
1088                         GXMAP(type,XK_End,                      GHOST_kKeyEnd);
1089                         GXMAP(type,XK_Page_Up,          GHOST_kKeyUpPage);
1090                         GXMAP(type,XK_Page_Down,        GHOST_kKeyDownPage);
1091
1092                         GXMAP(type,XK_Left,                     GHOST_kKeyLeftArrow);
1093                         GXMAP(type,XK_Right,            GHOST_kKeyRightArrow);
1094                         GXMAP(type,XK_Up,                       GHOST_kKeyUpArrow);
1095                         GXMAP(type,XK_Down,                     GHOST_kKeyDownArrow);
1096
1097                         GXMAP(type,XK_Caps_Lock,        GHOST_kKeyCapsLock);
1098                         GXMAP(type,XK_Scroll_Lock,      GHOST_kKeyScrollLock);
1099                         GXMAP(type,XK_Num_Lock,         GHOST_kKeyNumLock);
1100                         
1101                                 /* keypad events */
1102                                 
1103                         GXMAP(type,XK_KP_0,                     GHOST_kKeyNumpad0);
1104                         GXMAP(type,XK_KP_1,                     GHOST_kKeyNumpad1);
1105                         GXMAP(type,XK_KP_2,                     GHOST_kKeyNumpad2);
1106                         GXMAP(type,XK_KP_3,                     GHOST_kKeyNumpad3);
1107                         GXMAP(type,XK_KP_4,                     GHOST_kKeyNumpad4);
1108                         GXMAP(type,XK_KP_5,                     GHOST_kKeyNumpad5);
1109                         GXMAP(type,XK_KP_6,                     GHOST_kKeyNumpad6);
1110                         GXMAP(type,XK_KP_7,                     GHOST_kKeyNumpad7);
1111                         GXMAP(type,XK_KP_8,                     GHOST_kKeyNumpad8);
1112                         GXMAP(type,XK_KP_9,                     GHOST_kKeyNumpad9);
1113                         GXMAP(type,XK_KP_Decimal,       GHOST_kKeyNumpadPeriod);
1114
1115                         GXMAP(type,XK_KP_Insert,        GHOST_kKeyNumpad0);
1116                         GXMAP(type,XK_KP_End,           GHOST_kKeyNumpad1);
1117                         GXMAP(type,XK_KP_Down,          GHOST_kKeyNumpad2);
1118                         GXMAP(type,XK_KP_Page_Down,     GHOST_kKeyNumpad3);
1119                         GXMAP(type,XK_KP_Left,          GHOST_kKeyNumpad4);
1120                         GXMAP(type,XK_KP_Begin,         GHOST_kKeyNumpad5);
1121                         GXMAP(type,XK_KP_Right,         GHOST_kKeyNumpad6);
1122                         GXMAP(type,XK_KP_Home,          GHOST_kKeyNumpad7);
1123                         GXMAP(type,XK_KP_Up,            GHOST_kKeyNumpad8);
1124                         GXMAP(type,XK_KP_Page_Up,       GHOST_kKeyNumpad9);
1125                         GXMAP(type,XK_KP_Delete,        GHOST_kKeyNumpadPeriod);
1126
1127                         GXMAP(type,XK_KP_Enter,         GHOST_kKeyNumpadEnter);
1128                         GXMAP(type,XK_KP_Add,           GHOST_kKeyNumpadPlus);
1129                         GXMAP(type,XK_KP_Subtract,      GHOST_kKeyNumpadMinus);
1130                         GXMAP(type,XK_KP_Multiply,      GHOST_kKeyNumpadAsterisk);
1131                         GXMAP(type,XK_KP_Divide,        GHOST_kKeyNumpadSlash);
1132
1133                         /* Media keys in some keyboards and laptops with XFree86/Xorg */
1134 #ifdef WITH_XF86KEYSYM
1135                         GXMAP(type,XF86XK_AudioPlay,    GHOST_kKeyMediaPlay);
1136                         GXMAP(type,XF86XK_AudioStop,    GHOST_kKeyMediaStop);
1137                         GXMAP(type,XF86XK_AudioPrev,    GHOST_kKeyMediaFirst);
1138                         GXMAP(type,XF86XK_AudioRewind,  GHOST_kKeyMediaFirst);
1139                         GXMAP(type,XF86XK_AudioNext,    GHOST_kKeyMediaLast);
1140 #ifdef XF86XK_AudioForward /* Debian lenny's XF86keysym.h has no XF86XK_AudioForward define */
1141                         GXMAP(type,XF86XK_AudioForward, GHOST_kKeyMediaLast);
1142 #endif
1143 #endif
1144
1145                                 /* some extra sun cruft (NICE KEYBOARD!) */
1146 #ifdef __sun__
1147                         GXMAP(type,0xffde,                      GHOST_kKeyNumpad1);
1148                         GXMAP(type,0xffe0,                      GHOST_kKeyNumpad3);
1149                         GXMAP(type,0xffdc,                      GHOST_kKeyNumpad5);
1150                         GXMAP(type,0xffd8,                      GHOST_kKeyNumpad7);
1151                         GXMAP(type,0xffda,                      GHOST_kKeyNumpad9);
1152
1153                         GXMAP(type,0xffd6,                      GHOST_kKeyNumpadSlash);
1154                         GXMAP(type,0xffd7,                      GHOST_kKeyNumpadAsterisk);
1155 #endif
1156
1157                         default :
1158                                 type = GHOST_kKeyUnknown;
1159                                 break;
1160                 }
1161         }
1162
1163         return type;
1164 }
1165
1166 #undef GXMAP
1167
1168 /* from xclip.c xcout() v0.11 */
1169
1170 #define XCLIB_XCOUT_NONE                0 /* no context */
1171 #define XCLIB_XCOUT_SENTCONVSEL         1 /* sent a request */
1172 #define XCLIB_XCOUT_INCR                2 /* in an incr loop */
1173 #define XCLIB_XCOUT_FALLBACK            3 /* STRING failed, need fallback to UTF8 */
1174 #define XCLIB_XCOUT_FALLBACK_UTF8       4 /* UTF8 failed, move to compouned */
1175 #define XCLIB_XCOUT_FALLBACK_COMP       5 /* compouned failed, move to text. */
1176 #define XCLIB_XCOUT_FALLBACK_TEXT       6
1177
1178 // Retrieves the contents of a selections.
1179 void GHOST_SystemX11::getClipboard_xcout(XEvent evt,
1180         Atom sel, Atom target, unsigned char **txt,
1181         unsigned long *len, unsigned int *context) const
1182 {
1183         Atom pty_type;
1184         int pty_format;
1185         unsigned char *buffer;
1186         unsigned long pty_size, pty_items;
1187         unsigned char *ltxt= *txt;
1188
1189         vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();
1190         vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
1191         GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
1192         Window win = window->getXWindow();
1193
1194         switch (*context) {
1195                 // There is no context, do an XConvertSelection()
1196                 case XCLIB_XCOUT_NONE:
1197                         // Initialise return length to 0
1198                         if (*len > 0) {
1199                                 free(*txt);
1200                                 *len = 0;
1201                         }
1202
1203                         // Send a selection request
1204                         XConvertSelection(m_display, sel, target, m_xclip_out, win, CurrentTime);
1205                         *context = XCLIB_XCOUT_SENTCONVSEL;
1206                         return;
1207
1208                 case XCLIB_XCOUT_SENTCONVSEL:
1209                         if (evt.type != SelectionNotify)
1210                                 return;
1211
1212                         if (target == m_utf8_string && evt.xselection.property == None) {
1213                                 *context= XCLIB_XCOUT_FALLBACK_UTF8;
1214                                 return;
1215                         }
1216                         else if (target == m_compound_text && evt.xselection.property == None) {
1217                                 *context= XCLIB_XCOUT_FALLBACK_COMP;
1218                                 return;
1219                         }
1220                         else if (target == m_text && evt.xselection.property == None) {
1221                                 *context= XCLIB_XCOUT_FALLBACK_TEXT;
1222                                 return;
1223                         }
1224
1225                         // find the size and format of the data in property
1226                         XGetWindowProperty(m_display, win, m_xclip_out, 0, 0, False,
1227                                 AnyPropertyType, &pty_type, &pty_format,
1228                                 &pty_items, &pty_size, &buffer);
1229                         XFree(buffer);
1230
1231                         if (pty_type == m_incr) {
1232                                 // start INCR mechanism by deleting property
1233                                 XDeleteProperty(m_display, win, m_xclip_out);
1234                                 XFlush(m_display);
1235                                 *context = XCLIB_XCOUT_INCR;
1236                                 return;
1237                         }
1238
1239                         // if it's not incr, and not format == 8, then there's
1240                         // nothing in the selection (that xclip understands, anyway)
1241
1242                         if (pty_format != 8) {
1243                                 *context = XCLIB_XCOUT_NONE;
1244                                 return;
1245                         }
1246
1247                         // not using INCR mechanism, just read the property
1248                         XGetWindowProperty(m_display, win, m_xclip_out, 0, (long) pty_size,
1249                                         False, AnyPropertyType, &pty_type,
1250                                         &pty_format, &pty_items, &pty_size, &buffer);
1251
1252                         // finished with property, delete it
1253                         XDeleteProperty(m_display, win, m_xclip_out);
1254
1255                         // copy the buffer to the pointer for returned data
1256                         ltxt = (unsigned char *) malloc(pty_items);
1257                         memcpy(ltxt, buffer, pty_items);
1258
1259                         // set the length of the returned data
1260                         *len = pty_items;
1261                         *txt = ltxt;
1262
1263                         // free the buffer
1264                         XFree(buffer);
1265
1266                         *context = XCLIB_XCOUT_NONE;
1267
1268                         // complete contents of selection fetched, return 1
1269                         return;
1270
1271                 case XCLIB_XCOUT_INCR:
1272                         // To use the INCR method, we basically delete the
1273                         // property with the selection in it, wait for an
1274                         // event indicating that the property has been created,
1275                         // then read it, delete it, etc.
1276
1277                         // make sure that the event is relevant
1278                         if (evt.type != PropertyNotify)
1279                                 return;
1280
1281                         // skip unless the property has a new value
1282                         if (evt.xproperty.state != PropertyNewValue)
1283                                 return;
1284
1285                         // check size and format of the property
1286                         XGetWindowProperty(m_display, win, m_xclip_out, 0, 0, False,
1287                                 AnyPropertyType, &pty_type, &pty_format,
1288                                 &pty_items, &pty_size, (unsigned char **) &buffer);
1289
1290                         if (pty_format != 8) {
1291                                 // property does not contain text, delete it
1292                                 // to tell the other X client that we have read 
1293                                 // it and to send the next property
1294                                 XFree(buffer);
1295                                 XDeleteProperty(m_display, win, m_xclip_out);
1296                                 return;
1297                         }
1298
1299                         if (pty_size == 0) {
1300                                 // no more data, exit from loop
1301                                 XFree(buffer);
1302                                 XDeleteProperty(m_display, win, m_xclip_out);
1303                                 *context = XCLIB_XCOUT_NONE;
1304
1305                                 // this means that an INCR transfer is now
1306                                 // complete, return 1
1307                                 return;
1308                         }
1309
1310                         XFree(buffer);
1311
1312                         // if we have come this far, the propery contains
1313                         // text, we know the size.
1314                         XGetWindowProperty(m_display, win, m_xclip_out, 0, (long) pty_size,
1315                                 False, AnyPropertyType, &pty_type, &pty_format,
1316                                 &pty_items, &pty_size, (unsigned char **) &buffer);
1317
1318                         // allocate memory to accommodate data in *txt
1319                         if (*len == 0) {
1320                                 *len = pty_items;
1321                                 ltxt = (unsigned char *) malloc(*len);
1322                         }
1323                         else {
1324                                 *len += pty_items;
1325                                 ltxt = (unsigned char *) realloc(ltxt, *len);
1326                         }
1327
1328                         // add data to ltxt
1329                         memcpy(&ltxt[*len - pty_items], buffer, pty_items);
1330
1331                         *txt = ltxt;
1332                         XFree(buffer);
1333
1334                         // delete property to get the next item
1335                         XDeleteProperty(m_display, win, m_xclip_out);
1336                         XFlush(m_display);
1337                         return;
1338         }
1339         return;
1340 }
1341
1342 GHOST_TUns8 *GHOST_SystemX11::getClipboard(bool selection) const
1343 {
1344         Atom sseln;
1345         Atom target= m_string;
1346         Window owner;
1347
1348         // from xclip.c doOut() v0.11
1349         unsigned char *sel_buf;
1350         unsigned long sel_len= 0;
1351         XEvent evt;
1352         unsigned int context= XCLIB_XCOUT_NONE;
1353
1354         if (selection == True)
1355                 sseln= m_primary;
1356         else
1357                 sseln= m_clipboard;
1358
1359         vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();
1360         vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
1361         GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
1362         Window win = window->getXWindow();
1363
1364         /* check if we are the owner. */
1365         owner= XGetSelectionOwner(m_display, sseln);
1366         if (owner == win) {
1367                 if (sseln == m_clipboard) {
1368                         sel_buf= (unsigned char *)malloc(strlen(txt_cut_buffer)+1);
1369                         strcpy((char *)sel_buf, txt_cut_buffer);
1370                         return((GHOST_TUns8*)sel_buf);
1371                 }
1372                 else {
1373                         sel_buf= (unsigned char *)malloc(strlen(txt_select_buffer)+1);
1374                         strcpy((char *)sel_buf, txt_select_buffer);
1375                         return((GHOST_TUns8*)sel_buf);
1376                 }
1377         }
1378         else if (owner == None)
1379                 return(NULL);
1380
1381         while (1) {
1382                 /* only get an event if xcout() is doing something */
1383                 if (context != XCLIB_XCOUT_NONE)
1384                         XNextEvent(m_display, &evt);
1385
1386                 /* fetch the selection, or part of it */
1387                 getClipboard_xcout(evt, sseln, target, &sel_buf, &sel_len, &context);
1388
1389                 /* fallback is needed. set XA_STRING to target and restart the loop. */
1390                 if (context == XCLIB_XCOUT_FALLBACK) {
1391                         context= XCLIB_XCOUT_NONE;
1392                         target= m_string;
1393                         continue;
1394                 }
1395                 else if (context == XCLIB_XCOUT_FALLBACK_UTF8) {
1396                         /* utf8 fail, move to compouned text. */
1397                         context= XCLIB_XCOUT_NONE;
1398                         target= m_compound_text;
1399                         continue;
1400                 }
1401                 else if (context == XCLIB_XCOUT_FALLBACK_COMP) {
1402                         /* compouned text faile, move to text. */
1403                         context= XCLIB_XCOUT_NONE;
1404                         target= m_text;
1405                         continue;
1406                 }
1407
1408                 /* only continue if xcout() is doing something */
1409                 if (context == XCLIB_XCOUT_NONE)
1410                         break;
1411         }
1412
1413         if (sel_len) {
1414                 /* only print the buffer out, and free it, if it's not
1415                  * empty
1416                  */
1417                 unsigned char *tmp_data = (unsigned char*) malloc(sel_len+1);
1418                 memcpy((char*)tmp_data, (char*)sel_buf, sel_len);
1419                 tmp_data[sel_len] = '\0';
1420                 
1421                 if (sseln == m_string)
1422                         XFree(sel_buf);
1423                 else
1424                         free(sel_buf);
1425                 
1426                 return (GHOST_TUns8*)tmp_data;
1427         }
1428         return(NULL);
1429 }
1430
1431 void GHOST_SystemX11::putClipboard(GHOST_TInt8 *buffer, bool selection) const
1432 {
1433         Window m_window, owner;
1434
1435         vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();      
1436         vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
1437         GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
1438         m_window = window->getXWindow();
1439
1440         if (buffer) {
1441                 if (selection == False) {
1442                         XSetSelectionOwner(m_display, m_clipboard, m_window, CurrentTime);
1443                         owner= XGetSelectionOwner(m_display, m_clipboard);
1444                         if (txt_cut_buffer)
1445                                 free((void*)txt_cut_buffer);
1446
1447                         txt_cut_buffer = (char*) malloc(strlen(buffer)+1);
1448                         strcpy(txt_cut_buffer, buffer);
1449                 } else {
1450                         XSetSelectionOwner(m_display, m_primary, m_window, CurrentTime);
1451                         owner= XGetSelectionOwner(m_display, m_primary);
1452                         if (txt_select_buffer)
1453                                 free((void*)txt_select_buffer);
1454
1455                         txt_select_buffer = (char*) malloc(strlen(buffer)+1);
1456                         strcpy(txt_select_buffer, buffer);
1457                 }
1458
1459                 if (owner != m_window)
1460                         fprintf(stderr, "failed to own primary\n");
1461         }
1462 }