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