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