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