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