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