=bmesh= merge from trunk at r36529
[blender.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         if (playingEvents(&anyProcessed)) {
397                 return anyProcessed;
398         }
399         
400         do {
401                 GHOST_TimerManager* timerMgr = getTimerManager();
402                 
403                 if (waitForEvent && m_dirty_windows.empty() && !XPending(m_display)) {
404                         GHOST_TUns64 next = timerMgr->nextFireTime();
405                         
406                         if (next==GHOST_kFireTimeNever) {
407                                 SleepTillEvent(m_display, -1);
408                         } else {
409                                 GHOST_TInt64 maxSleep = next - getMilliSeconds();
410
411                                 if(maxSleep >= 0)
412                                         SleepTillEvent(m_display, next - getMilliSeconds());
413                         }
414                 }
415                 
416                 if (timerMgr->fireTimers(getMilliSeconds())) {
417                         anyProcessed = true;
418                 }
419                 
420                 while (XPending(m_display)) {
421                         XEvent xevent;
422                         XNextEvent(m_display, &xevent);
423                         processEvent(&xevent);
424                         anyProcessed = true;
425                 }
426                 
427                 if (generateWindowExposeEvents()) {
428                         anyProcessed = true;
429                 }
430         } while (waitForEvent && !anyProcessed);
431         
432         return anyProcessed;
433 }
434
435         void
436 GHOST_SystemX11::processEvent(XEvent *xe)
437 {
438         GHOST_WindowX11 * window = findGhostWindow(xe->xany.window);    
439         GHOST_Event * g_event = NULL;
440
441         if (!window) {
442                 return;
443         }
444         
445         switch (xe->type) {
446                 case Expose:
447                 {
448                         XExposeEvent & xee = xe->xexpose;
449
450                         if (xee.count == 0) {
451                                 // Only generate a single expose event
452                                 // per read of the event queue.
453
454                                 g_event = new
455                                 GHOST_Event(
456                                         getMilliSeconds(),
457                                         GHOST_kEventWindowUpdate,
458                                         window
459                                 );
460                         }
461                         break;
462                 }
463
464                 case MotionNotify:
465                 {
466                         XMotionEvent &xme = xe->xmotion;
467                         
468                         if(window->getCursorGrabMode() != GHOST_kGrabDisable && window->getCursorGrabMode() != GHOST_kGrabNormal)
469                         {
470                                 GHOST_TInt32 x_new= xme.x_root;
471                                 GHOST_TInt32 y_new= xme.y_root;
472                                 GHOST_TInt32 x_accum, y_accum;
473                                 GHOST_Rect bounds;
474
475                                 /* fallback to window bounds */
476                                 if(window->getCursorGrabBounds(bounds)==GHOST_kFailure)
477                                         window->getClientBounds(bounds);
478
479                                 /* could also clamp to screen bounds
480                                  * wrap with a window outside the view will fail atm  */
481                                 bounds.wrapPoint(x_new, y_new, 8); /* offset of one incase blender is at screen bounds */
482                                 window->getCursorGrabAccum(x_accum, y_accum);
483
484                                 if(x_new != xme.x_root || y_new != xme.y_root) {
485                                         if (xme.time > m_last_warp) {
486                                                 /* when wrapping we don't need to add an event because the
487                                                  * setCursorPosition call will cause a new event after */
488                                                 setCursorPosition(x_new, y_new); /* wrap */
489                                                 window->setCursorGrabAccum(x_accum + (xme.x_root - x_new), y_accum + (xme.y_root - y_new));
490                                                 m_last_warp = lastEventTime(xme.time);
491                                         } else {
492                                                 setCursorPosition(x_new, y_new); /* wrap but don't accumulate */
493                                         }
494                                 }
495                                 else {
496                                         g_event = new
497                                         GHOST_EventCursor(
498                                                 getMilliSeconds(),
499                                                 GHOST_kEventCursorMove,
500                                                 window,
501                                                 xme.x_root + x_accum,
502                                                 xme.y_root + y_accum
503                                         );
504                                 }
505                         }
506                         else {
507                                 g_event = new
508                                 GHOST_EventCursor(
509                                         getMilliSeconds(),
510                                         GHOST_kEventCursorMove,
511                                         window,
512                                         xme.x_root,
513                                         xme.y_root
514                                 );
515                         }
516                         break;
517                 }
518
519                 case KeyPress:
520                 case KeyRelease:
521                 {
522                         XKeyEvent *xke = &(xe->xkey);
523                 
524                         KeySym key_sym = XLookupKeysym(xke,0);
525                         char ascii;
526                         
527                         GHOST_TKey gkey = convertXKey(key_sym);
528                         GHOST_TEventType type = (xke->type == KeyPress) ? 
529                                 GHOST_kEventKeyDown : GHOST_kEventKeyUp;
530                         
531                         if (!XLookupString(xke, &ascii, 1, NULL, NULL)) {
532                                 ascii = '\0';
533                         }
534                         
535                         g_event = new
536                         GHOST_EventKey(
537                                 getMilliSeconds(),
538                                 type,
539                                 window,
540                                 gkey,
541                                 ascii
542                         );
543                         
544                 break;
545                 }
546
547                 case ButtonPress:
548                 case ButtonRelease:
549                 {
550                         XButtonEvent & xbe = xe->xbutton;
551                         GHOST_TButtonMask gbmask = GHOST_kButtonMaskLeft;
552                         GHOST_TEventType type = (xbe.type == ButtonPress) ? 
553                                 GHOST_kEventButtonDown : GHOST_kEventButtonUp;
554
555                         /* process wheel mouse events and break, only pass on press events */
556                         if(xbe.button == Button4) {
557                                 if(xbe.type == ButtonPress)
558                                         g_event = new GHOST_EventWheel(getMilliSeconds(), window, 1);
559                                 break;
560                         }
561                         else if(xbe.button == Button5) {
562                                 if(xbe.type == ButtonPress)
563                                         g_event = new GHOST_EventWheel(getMilliSeconds(), window, -1);
564                                 break;
565                         }
566                         
567                         /* process rest of normal mouse buttons */
568                         if(xbe.button == Button1)
569                                 gbmask = GHOST_kButtonMaskLeft;
570                         else if(xbe.button == Button2)
571                                 gbmask = GHOST_kButtonMaskMiddle;
572                         else if(xbe.button == Button3)
573                                 gbmask = GHOST_kButtonMaskRight;
574                         /* It seems events 6 and 7 are for horizontal scrolling.
575                         * you can re-order button mapping like this... (swaps 6,7 with 8,9)
576                         *   xmodmap -e "pointer = 1 2 3 4 5 8 9 6 7" 
577                         */
578                         else if(xbe.button == 8)
579                                 gbmask = GHOST_kButtonMaskButton4;
580                         else if(xbe.button == 9)
581                                 gbmask = GHOST_kButtonMaskButton5;
582                         else
583                                 break;
584
585                         g_event = new
586                         GHOST_EventButton(
587                                 getMilliSeconds(),
588                                 type,
589                                 window,
590                                 gbmask
591                         );
592                         break;
593                 }
594                         
595                         // change of size, border, layer etc.
596                 case ConfigureNotify:
597                 {
598                         /* XConfigureEvent & xce = xe->xconfigure; */
599
600                         g_event = new 
601                         GHOST_Event(
602                                 getMilliSeconds(),
603                                 GHOST_kEventWindowSize,
604                                 window
605                         );                      
606                         break;
607                 }
608
609                 case FocusIn:
610                 case FocusOut:
611                 {
612                         XFocusChangeEvent &xfe = xe->xfocus;
613                 
614                         // May have to look at the type of event and filter some
615                         // out.
616                                                                         
617                         GHOST_TEventType gtype = (xfe.type == FocusIn) ? 
618                                 GHOST_kEventWindowActivate : GHOST_kEventWindowDeactivate;
619
620                         g_event = new 
621                         GHOST_Event(    
622                                 getMilliSeconds(),
623                                 gtype,
624                                 window
625                         );
626                         break;
627
628                 }
629                 case ClientMessage:
630                 {
631                         XClientMessageEvent & xcme = xe->xclient;
632
633 #ifndef __sgi                   
634                         if (((Atom)xcme.data.l[0]) == m_delete_window_atom) {
635                                 g_event = new 
636                                 GHOST_Event(    
637                                         getMilliSeconds(),
638                                         GHOST_kEventWindowClose,
639                                         window
640                                 );
641                         } else 
642 #endif
643                         if (sNdofInfo.currValues) {
644                                 static GHOST_TEventNDOFData data = {0,0,0,0,0,0,0,0,0,0,0};
645                                 if (xcme.message_type == sNdofInfo.motionAtom)
646                                 {
647                                         data.changed = 1;
648                                         data.delta = xcme.data.s[8] - data.time;
649                                         data.time = xcme.data.s[8];
650                                         data.tx = xcme.data.s[2] >> 2;
651                                         data.ty = xcme.data.s[3] >> 2;
652                                         data.tz = xcme.data.s[4] >> 2;
653                                         data.rx = xcme.data.s[5];
654                                         data.ry = xcme.data.s[6];
655                                         data.rz =-xcme.data.s[7];
656                                         g_event = new GHOST_EventNDOF(getMilliSeconds(),
657                                                                       GHOST_kEventNDOFMotion,
658                                                                       window, data);
659                                 } else if (xcme.message_type == sNdofInfo.btnPressAtom) {
660                                         data.changed = 2;
661                                         data.delta = xcme.data.s[8] - data.time;
662                                         data.time = xcme.data.s[8];
663                                         data.buttons = xcme.data.s[2];
664                                         g_event = new GHOST_EventNDOF(getMilliSeconds(),
665                                                                       GHOST_kEventNDOFButton,
666                                                                       window, data);
667                                 }
668                         } else if (((Atom)xcme.data.l[0]) == m_wm_take_focus) {
669                                 XWindowAttributes attr;
670                                 Window fwin;
671                                 int revert_to;
672
673                                 /* as ICCCM say, we need reply this event
674                                  * with a SetInputFocus, the data[1] have
675                                  * the valid timestamp (send by the wm).
676                                  *
677                                  * Some WM send this event before the
678                                  * window is really mapped (for example
679                                  * change from virtual desktop), so we need
680                                  * to be sure that our windows is mapped
681                                  * or this call fail and close blender.
682                                  */
683                                 if (XGetWindowAttributes(m_display, xcme.window, &attr) == True) {
684                                         if (XGetInputFocus(m_display, &fwin, &revert_to) == True) {
685                                                 if (attr.map_state == IsViewable) {
686                                                         if (fwin != xcme.window)
687                                                                 XSetInputFocus(m_display, xcme.window, RevertToParent, xcme.data.l[1]);
688                                                 }
689                                         }
690                                 }
691                         } else {
692                                 /* Unknown client message, ignore */
693                         }
694                         break;
695                 }
696                 
697                 case DestroyNotify:
698                         ::exit(-1);     
699                 // We're not interested in the following things.(yet...)
700                 case NoExpose : 
701                 case GraphicsExpose :
702                         break;
703                 
704                 case EnterNotify:
705                 case LeaveNotify:
706                 {
707                         // XCrossingEvents pointer leave enter window.
708                         // also do cursor move here, MotionNotify only
709                         // happens when motion starts & ends inside window
710                         XCrossingEvent &xce = xe->xcrossing;
711                         
712                         g_event = new 
713                         GHOST_EventCursor(
714                                 getMilliSeconds(),
715                                 GHOST_kEventCursorMove,
716                                 window,
717                                 xce.x_root,
718                                 xce.y_root
719                         );
720                         break;
721                 }
722                 case MapNotify:
723                         /*
724                          * From ICCCM:
725                          * [ Clients can select for StructureNotify on their
726                          *   top-level windows to track transition between
727                          *   Normal and Iconic states. Receipt of a MapNotify
728                          *   event will indicate a transition to the Normal
729                          *   state, and receipt of an UnmapNotify event will
730                          *   indicate a transition to the Iconic state. ]
731                          */
732                         if (window->m_post_init == True) {
733                                 /*
734                                  * Now we are sure that the window is
735                                  * mapped, so only need change the state.
736                                  */
737                                 window->setState (window->m_post_state);
738                                 window->m_post_init = False;
739                         }
740                         break;
741                 case UnmapNotify:
742                         break;
743                 case MappingNotify:
744                 case ReparentNotify:
745                         break;
746                 case SelectionRequest:
747                 {
748                         XEvent nxe;
749                         Atom target, string, compound_text, c_string;
750                         XSelectionRequestEvent *xse = &xe->xselectionrequest;
751                         
752                         target = XInternAtom(m_display, "TARGETS", False);
753                         string = XInternAtom(m_display, "STRING", False);
754                         compound_text = XInternAtom(m_display, "COMPOUND_TEXT", False);
755                         c_string = XInternAtom(m_display, "C_STRING", False);
756                         
757                         /* support obsolete clients */
758                         if (xse->property == None) {
759                                 xse->property = xse->target;
760                         }
761                         
762                         nxe.xselection.type = SelectionNotify;
763                         nxe.xselection.requestor = xse->requestor;
764                         nxe.xselection.property = xse->property;
765                         nxe.xselection.display = xse->display;
766                         nxe.xselection.selection = xse->selection;
767                         nxe.xselection.target = xse->target;
768                         nxe.xselection.time = xse->time;
769                         
770                         /*Check to see if the requestor is asking for String*/
771                         if(xse->target == string || xse->target == compound_text || xse->target == c_string) {
772                                 if (xse->selection == XInternAtom(m_display, "PRIMARY", False)) {
773                                         XChangeProperty(m_display, xse->requestor, xse->property, xse->target, 8, PropModeReplace, (unsigned char*)txt_select_buffer, strlen(txt_select_buffer));
774                                 } else if (xse->selection == XInternAtom(m_display, "CLIPBOARD", False)) {
775                                         XChangeProperty(m_display, xse->requestor, xse->property, xse->target, 8, PropModeReplace, (unsigned char*)txt_cut_buffer, strlen(txt_cut_buffer));
776                                 }
777                         } else if (xse->target == target) {
778                                 Atom alist[4];
779                                 alist[0] = target;
780                                 alist[1] = string;
781                                 alist[2] = compound_text;
782                                 alist[3] = c_string;
783                                 XChangeProperty(m_display, xse->requestor, xse->property, xse->target, 32, PropModeReplace, (unsigned char*)alist, 4);
784                                 XFlush(m_display);
785                         } else  {
786                                 //Change property to None because we do not support anything but STRING
787                                 nxe.xselection.property = None;
788                         }
789                         
790                         //Send the event to the client 0 0 == False, SelectionNotify
791                         XSendEvent(m_display, xse->requestor, 0, 0, &nxe);
792                         XFlush(m_display);
793                         break;
794                 }
795                 
796                 default: {
797                         if(xe->type == window->GetXTablet().MotionEvent) 
798                         {
799                                 XDeviceMotionEvent* data = (XDeviceMotionEvent*)xe;
800                                 window->GetXTablet().CommonData.Pressure= 
801                                         data->axis_data[2]/((float)window->GetXTablet().PressureLevels);
802                         
803                         /* the (short) cast and the &0xffff is bizarre and unexplained anywhere,
804                          * but I got garbage data without it. Found it in the xidump.c source --matt */
805                                 window->GetXTablet().CommonData.Xtilt= 
806                                         (short)(data->axis_data[3]&0xffff)/((float)window->GetXTablet().XtiltLevels);
807                                 window->GetXTablet().CommonData.Ytilt= 
808                                         (short)(data->axis_data[4]&0xffff)/((float)window->GetXTablet().YtiltLevels);
809                         }
810                         else if(xe->type == window->GetXTablet().ProxInEvent) 
811                         {
812                                 XProximityNotifyEvent* data = (XProximityNotifyEvent*)xe;
813                                 if(data->deviceid == window->GetXTablet().StylusID)
814                                         window->GetXTablet().CommonData.Active= GHOST_kTabletModeStylus;
815                                 else if(data->deviceid == window->GetXTablet().EraserID)
816                                         window->GetXTablet().CommonData.Active= GHOST_kTabletModeEraser;
817                         }
818                         else if(xe->type == window->GetXTablet().ProxOutEvent)
819                                 window->GetXTablet().CommonData.Active= GHOST_kTabletModeNone;
820
821                         break;
822                 }
823         }
824
825         if (g_event) {
826                 pushEvent(g_event);
827         }
828 }
829
830         void *
831 GHOST_SystemX11::
832 prepareNdofInfo(volatile GHOST_TEventNDOFData *currentNdofValues)
833 {
834         const vector<GHOST_IWindow*>& v(m_windowManager->getWindows());
835         if (v.size() > 0)
836                 sNdofInfo.window = static_cast<GHOST_WindowX11*>(v[0])->getXWindow();
837         sNdofInfo.display = m_display;
838         sNdofInfo.currValues = currentNdofValues;
839         return (void*)&sNdofInfo;
840 }
841
842         GHOST_TSuccess 
843 GHOST_SystemX11::
844 getModifierKeys(
845         GHOST_ModifierKeys& keys
846 ) const {
847         if (this->playingEvents(NULL)) {
848                 return getEventManager()->getModifierKeys(keys);
849         }
850         
851         // analyse the masks retuned from XQueryPointer.
852
853         memset((void *)m_keyboard_vector,0,sizeof(m_keyboard_vector));
854
855         XQueryKeymap(m_display,(char *)m_keyboard_vector);
856
857         // now translate key symobols into keycodes and
858         // test with vector.
859
860         const KeyCode shift_l = XKeysymToKeycode(m_display,XK_Shift_L);
861         const KeyCode shift_r = XKeysymToKeycode(m_display,XK_Shift_R);
862         const KeyCode control_l = XKeysymToKeycode(m_display,XK_Control_L);
863         const KeyCode control_r = XKeysymToKeycode(m_display,XK_Control_R);
864         const KeyCode alt_l = XKeysymToKeycode(m_display,XK_Alt_L);
865         const KeyCode alt_r = XKeysymToKeycode(m_display,XK_Alt_R);
866         const KeyCode super_l = XKeysymToKeycode(m_display,XK_Super_L);
867         const KeyCode super_r = XKeysymToKeycode(m_display,XK_Super_R);
868
869         // Shift
870         if ((m_keyboard_vector[shift_l >> 3] >> (shift_l & 7)) & 1) {
871                 keys.set(GHOST_kModifierKeyLeftShift,true);
872         } else {
873                 keys.set(GHOST_kModifierKeyLeftShift,false);
874         }
875         if ((m_keyboard_vector[shift_r >> 3] >> (shift_r & 7)) & 1) {
876
877                 keys.set(GHOST_kModifierKeyRightShift,true);
878         } else {
879                 keys.set(GHOST_kModifierKeyRightShift,false);
880         }
881
882         // control (weep)
883         if ((m_keyboard_vector[control_l >> 3] >> (control_l & 7)) & 1) {
884                 keys.set(GHOST_kModifierKeyLeftControl,true);
885         } else {
886                 keys.set(GHOST_kModifierKeyLeftControl,false);
887         }
888         if ((m_keyboard_vector[control_r >> 3] >> (control_r & 7)) & 1) {
889                 keys.set(GHOST_kModifierKeyRightControl,true);
890         } else {
891                 keys.set(GHOST_kModifierKeyRightControl,false);
892         }
893
894         // Alt (yawn)
895         if ((m_keyboard_vector[alt_l >> 3] >> (alt_l & 7)) & 1) {
896                 keys.set(GHOST_kModifierKeyLeftAlt,true);
897         } else {
898                 keys.set(GHOST_kModifierKeyLeftAlt,false);
899         }       
900         if ((m_keyboard_vector[alt_r >> 3] >> (alt_r & 7)) & 1) {
901                 keys.set(GHOST_kModifierKeyRightAlt,true);
902         } else {
903                 keys.set(GHOST_kModifierKeyRightAlt,false);
904         }
905
906         // Super (Windows) - only one GHOST-kModifierKeyOS, so mapping
907         // to either
908         if ( ((m_keyboard_vector[super_l >> 3] >> (super_l & 7)) & 1) || 
909              ((m_keyboard_vector[super_r >> 3] >> (super_r & 7)) & 1) ) {
910                 keys.set(GHOST_kModifierKeyOS,true);
911         } else {
912                 keys.set(GHOST_kModifierKeyOS,false);
913         }
914         return GHOST_kSuccess;
915 }
916
917         GHOST_TSuccess 
918 GHOST_SystemX11::
919 getButtons(
920         GHOST_Buttons& buttons
921 ) const {
922
923         Window root_return, child_return;
924         int rx,ry,wx,wy;
925         unsigned int mask_return;
926
927         if (XQueryPointer(
928                 m_display,
929                 RootWindow(m_display,DefaultScreen(m_display)),
930                 &root_return,
931                 &child_return,
932                 &rx,&ry,
933                 &wx,&wy,
934                 &mask_return
935         ) == False) {
936                 return GHOST_kFailure;
937         } else {
938
939                 if (mask_return & Button1Mask) {
940                         buttons.set(GHOST_kButtonMaskLeft,true);
941                 } else {
942                         buttons.set(GHOST_kButtonMaskLeft,false);
943                 }
944
945                 if (mask_return & Button2Mask) {
946                         buttons.set(GHOST_kButtonMaskMiddle,true);
947                 } else {
948                         buttons.set(GHOST_kButtonMaskMiddle,false);
949                 }
950
951                 if (mask_return & Button3Mask) {
952                         buttons.set(GHOST_kButtonMaskRight,true);
953                 } else {
954                         buttons.set(GHOST_kButtonMaskRight,false);
955                 }
956         }       
957
958         return GHOST_kSuccess;
959 }
960
961
962         GHOST_TSuccess 
963 GHOST_SystemX11::
964 getCursorPosition(
965         GHOST_TInt32& x,
966         GHOST_TInt32& y
967 ) const {
968
969         Window root_return, child_return;
970         int rx,ry,wx,wy;
971         unsigned int mask_return;
972         
973         if (playingEvents(NULL)) {
974                 return getEventManager()->getCursorPosition(x, y);
975         }
976         
977         if (XQueryPointer(
978                 m_display,
979                 RootWindow(m_display,DefaultScreen(m_display)),
980                 &root_return,
981                 &child_return,
982                 &rx,&ry,
983                 &wx,&wy,
984                 &mask_return
985         ) == False) {
986                 return GHOST_kFailure;
987         } else {
988                 x = rx;
989                 y = ry;
990         }       
991         return GHOST_kSuccess;
992 }
993
994
995         GHOST_TSuccess 
996 GHOST_SystemX11::
997 setCursorPosition(
998         GHOST_TInt32 x,
999         GHOST_TInt32 y
1000 ) {
1001
1002         // This is a brute force move in screen coordinates
1003         // XWarpPointer does relative moves so first determine the
1004         // current pointer position.
1005
1006         int cx,cy;
1007         if (getCursorPosition(cx,cy) == GHOST_kFailure) {
1008                 return GHOST_kFailure;
1009         }
1010
1011         int relx = x-cx;
1012         int rely = y-cy;
1013
1014         XWarpPointer(m_display,None,None,0,0,0,0,relx,rely);
1015         XSync(m_display, 0); /* Sync to process all requests */
1016         
1017         return GHOST_kSuccess;
1018 }
1019
1020
1021         void
1022 GHOST_SystemX11::
1023 addDirtyWindow(
1024         GHOST_WindowX11 * bad_wind
1025 ){
1026
1027         GHOST_ASSERT((bad_wind != NULL), "addDirtyWindow() NULL ptr trapped (window)");
1028         
1029         m_dirty_windows.push_back(bad_wind);
1030 }
1031
1032
1033         bool
1034 GHOST_SystemX11::
1035 generateWindowExposeEvents(
1036 ){
1037
1038         vector<GHOST_WindowX11 *>::iterator w_start = m_dirty_windows.begin();
1039         vector<GHOST_WindowX11 *>::const_iterator w_end = m_dirty_windows.end();
1040         bool anyProcessed = false;
1041         
1042         for (;w_start != w_end; ++w_start) {
1043                 GHOST_Event * g_event = new 
1044                         GHOST_Event(
1045                                 getMilliSeconds(),
1046                                 GHOST_kEventWindowUpdate,
1047                                 *w_start
1048                         );                      
1049
1050                 (*w_start)->validate(); 
1051                 
1052                 if (g_event) {
1053                         pushEvent(g_event);
1054                         anyProcessed = true;
1055                 }
1056         }
1057
1058         m_dirty_windows.clear();
1059         return anyProcessed;
1060 }
1061
1062 #define GXMAP(k,x,y) case x: k = y; break; 
1063
1064         GHOST_TKey
1065 GHOST_SystemX11::
1066 convertXKey(
1067         KeySym key
1068 ){
1069         GHOST_TKey type;
1070
1071         if ((key >= XK_A) && (key <= XK_Z)) {
1072                 type = GHOST_TKey( key - XK_A + int(GHOST_kKeyA));
1073         } else if ((key >= XK_a) && (key <= XK_z)) {
1074                 type = GHOST_TKey(key - XK_a + int(GHOST_kKeyA));
1075         } else if ((key >= XK_0) && (key <= XK_9)) {
1076                 type = GHOST_TKey(key - XK_0 + int(GHOST_kKey0));
1077         } else if ((key >= XK_F1) && (key <= XK_F24)) {
1078                 type = GHOST_TKey(key - XK_F1 + int(GHOST_kKeyF1));
1079 #if defined(__sun) || defined(__sun__) 
1080                 /* This is a bit of a hack, but it looks like sun
1081                    Used F11 and friends for its special keys Stop,again etc..
1082                    So this little patch enables F11 and F12 to work as expected
1083                    following link has documentation on it: 
1084                    http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4734408
1085                    also from /usr/include/X11/Sunkeysym.h 
1086 #define SunXK_F36               0x1005FF10      // Labeled F11
1087 #define SunXK_F37               0x1005FF11      // Labeled F12 
1088
1089                                 mein@cs.umn.edu
1090                  */
1091                 
1092         } else if (key == 268828432) {
1093                 type = GHOST_kKeyF11;
1094         } else if (key == 268828433) {
1095                 type = GHOST_kKeyF12;
1096 #endif
1097         } else {
1098                 switch(key) {
1099                         GXMAP(type,XK_BackSpace,        GHOST_kKeyBackSpace);
1100                         GXMAP(type,XK_Tab,              GHOST_kKeyTab);
1101                         GXMAP(type,XK_Return,           GHOST_kKeyEnter);
1102                         GXMAP(type,XK_Escape,           GHOST_kKeyEsc);
1103                         GXMAP(type,XK_space,            GHOST_kKeySpace);
1104                         
1105                         GXMAP(type,XK_Linefeed,         GHOST_kKeyLinefeed);
1106                         GXMAP(type,XK_semicolon,        GHOST_kKeySemicolon);
1107                         GXMAP(type,XK_period,           GHOST_kKeyPeriod);
1108                         GXMAP(type,XK_comma,            GHOST_kKeyComma);
1109                         GXMAP(type,XK_quoteright,       GHOST_kKeyQuote);
1110                         GXMAP(type,XK_quoteleft,        GHOST_kKeyAccentGrave);
1111                         GXMAP(type,XK_minus,            GHOST_kKeyMinus);
1112                         GXMAP(type,XK_slash,            GHOST_kKeySlash);
1113                         GXMAP(type,XK_backslash,        GHOST_kKeyBackslash);
1114                         GXMAP(type,XK_equal,            GHOST_kKeyEqual);
1115                         GXMAP(type,XK_bracketleft,      GHOST_kKeyLeftBracket);
1116                         GXMAP(type,XK_bracketright,     GHOST_kKeyRightBracket);
1117                         GXMAP(type,XK_Pause,            GHOST_kKeyPause);
1118                         
1119                         GXMAP(type,XK_Shift_L,          GHOST_kKeyLeftShift);
1120                         GXMAP(type,XK_Shift_R,          GHOST_kKeyRightShift);
1121                         GXMAP(type,XK_Control_L,        GHOST_kKeyLeftControl);
1122                         GXMAP(type,XK_Control_R,        GHOST_kKeyRightControl);
1123                         GXMAP(type,XK_Alt_L,            GHOST_kKeyLeftAlt);
1124                         GXMAP(type,XK_Alt_R,            GHOST_kKeyRightAlt);
1125                         GXMAP(type,XK_Super_L,          GHOST_kKeyOS);
1126                         GXMAP(type,XK_Super_R,          GHOST_kKeyOS);
1127
1128                         GXMAP(type,XK_Insert,           GHOST_kKeyInsert);
1129                         GXMAP(type,XK_Delete,           GHOST_kKeyDelete);
1130                         GXMAP(type,XK_Home,                     GHOST_kKeyHome);
1131                         GXMAP(type,XK_End,                      GHOST_kKeyEnd);
1132                         GXMAP(type,XK_Page_Up,          GHOST_kKeyUpPage);
1133                         GXMAP(type,XK_Page_Down,        GHOST_kKeyDownPage);
1134
1135                         GXMAP(type,XK_Left,                     GHOST_kKeyLeftArrow);
1136                         GXMAP(type,XK_Right,            GHOST_kKeyRightArrow);
1137                         GXMAP(type,XK_Up,                       GHOST_kKeyUpArrow);
1138                         GXMAP(type,XK_Down,                     GHOST_kKeyDownArrow);
1139
1140                         GXMAP(type,XK_Caps_Lock,        GHOST_kKeyCapsLock);
1141                         GXMAP(type,XK_Scroll_Lock,      GHOST_kKeyScrollLock);
1142                         GXMAP(type,XK_Num_Lock,         GHOST_kKeyNumLock);
1143                         
1144                                 /* keypad events */
1145                                 
1146                         GXMAP(type,XK_KP_0,                     GHOST_kKeyNumpad0);
1147                         GXMAP(type,XK_KP_1,                     GHOST_kKeyNumpad1);
1148                         GXMAP(type,XK_KP_2,                     GHOST_kKeyNumpad2);
1149                         GXMAP(type,XK_KP_3,                     GHOST_kKeyNumpad3);
1150                         GXMAP(type,XK_KP_4,                     GHOST_kKeyNumpad4);
1151                         GXMAP(type,XK_KP_5,                     GHOST_kKeyNumpad5);
1152                         GXMAP(type,XK_KP_6,                     GHOST_kKeyNumpad6);
1153                         GXMAP(type,XK_KP_7,                     GHOST_kKeyNumpad7);
1154                         GXMAP(type,XK_KP_8,                     GHOST_kKeyNumpad8);
1155                         GXMAP(type,XK_KP_9,                     GHOST_kKeyNumpad9);
1156                         GXMAP(type,XK_KP_Decimal,       GHOST_kKeyNumpadPeriod);
1157
1158                         GXMAP(type,XK_KP_Insert,        GHOST_kKeyNumpad0);
1159                         GXMAP(type,XK_KP_End,           GHOST_kKeyNumpad1);
1160                         GXMAP(type,XK_KP_Down,          GHOST_kKeyNumpad2);
1161                         GXMAP(type,XK_KP_Page_Down,     GHOST_kKeyNumpad3);
1162                         GXMAP(type,XK_KP_Left,          GHOST_kKeyNumpad4);
1163                         GXMAP(type,XK_KP_Begin,         GHOST_kKeyNumpad5);
1164                         GXMAP(type,XK_KP_Right,         GHOST_kKeyNumpad6);
1165                         GXMAP(type,XK_KP_Home,          GHOST_kKeyNumpad7);
1166                         GXMAP(type,XK_KP_Up,            GHOST_kKeyNumpad8);
1167                         GXMAP(type,XK_KP_Page_Up,       GHOST_kKeyNumpad9);
1168                         GXMAP(type,XK_KP_Delete,        GHOST_kKeyNumpadPeriod);
1169
1170                         GXMAP(type,XK_KP_Enter,         GHOST_kKeyNumpadEnter);
1171                         GXMAP(type,XK_KP_Add,           GHOST_kKeyNumpadPlus);
1172                         GXMAP(type,XK_KP_Subtract,      GHOST_kKeyNumpadMinus);
1173                         GXMAP(type,XK_KP_Multiply,      GHOST_kKeyNumpadAsterisk);
1174                         GXMAP(type,XK_KP_Divide,        GHOST_kKeyNumpadSlash);
1175
1176                         /* Media keys in some keyboards and laptops with XFree86/Xorg */
1177 #ifdef WITH_XF86KEYSYM
1178                         GXMAP(type,XF86XK_AudioPlay,    GHOST_kKeyMediaPlay);
1179                         GXMAP(type,XF86XK_AudioStop,    GHOST_kKeyMediaStop);
1180                         GXMAP(type,XF86XK_AudioPrev,    GHOST_kKeyMediaFirst);
1181                         GXMAP(type,XF86XK_AudioRewind,  GHOST_kKeyMediaFirst);
1182                         GXMAP(type,XF86XK_AudioNext,    GHOST_kKeyMediaLast);
1183                         GXMAP(type,XF86XK_AudioForward, GHOST_kKeyMediaLast);
1184 #endif
1185
1186                                 /* some extra sun cruft (NICE KEYBOARD!) */
1187 #ifdef __sun__
1188                         GXMAP(type,0xffde,                      GHOST_kKeyNumpad1);
1189                         GXMAP(type,0xffe0,                      GHOST_kKeyNumpad3);
1190                         GXMAP(type,0xffdc,                      GHOST_kKeyNumpad5);
1191                         GXMAP(type,0xffd8,                      GHOST_kKeyNumpad7);
1192                         GXMAP(type,0xffda,                      GHOST_kKeyNumpad9);
1193
1194                         GXMAP(type,0xffd6,                      GHOST_kKeyNumpadSlash);
1195                         GXMAP(type,0xffd7,                      GHOST_kKeyNumpadAsterisk);
1196 #endif
1197
1198                         default :
1199                                 type = GHOST_kKeyUnknown;
1200                                 break;
1201                 }
1202         }
1203
1204         return type;
1205 }
1206
1207 #undef GXMAP
1208
1209 /* from xclip.c xcout() v0.11 */
1210
1211 #define XCLIB_XCOUT_NONE                0 /* no context */
1212 #define XCLIB_XCOUT_SENTCONVSEL         1 /* sent a request */
1213 #define XCLIB_XCOUT_INCR                2 /* in an incr loop */
1214 #define XCLIB_XCOUT_FALLBACK            3 /* STRING failed, need fallback to UTF8 */
1215 #define XCLIB_XCOUT_FALLBACK_UTF8       4 /* UTF8 failed, move to compouned */
1216 #define XCLIB_XCOUT_FALLBACK_COMP       5 /* compouned failed, move to text. */
1217 #define XCLIB_XCOUT_FALLBACK_TEXT       6
1218
1219 // Retrieves the contents of a selections.
1220 void GHOST_SystemX11::getClipboard_xcout(XEvent evt,
1221         Atom sel, Atom target, unsigned char **txt,
1222         unsigned long *len, unsigned int *context) const
1223 {
1224         Atom pty_type;
1225         int pty_format;
1226         unsigned char *buffer;
1227         unsigned long pty_size, pty_items;
1228         unsigned char *ltxt= *txt;
1229
1230         vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();
1231         vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
1232         GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
1233         Window win = window->getXWindow();
1234
1235         switch (*context) {
1236                 // There is no context, do an XConvertSelection()
1237                 case XCLIB_XCOUT_NONE:
1238                         // Initialise return length to 0
1239                         if (*len > 0) {
1240                                 free(*txt);
1241                                 *len = 0;
1242                         }
1243
1244                         // Send a selection request
1245                         XConvertSelection(m_display, sel, target, m_xclip_out, win, CurrentTime);
1246                         *context = XCLIB_XCOUT_SENTCONVSEL;
1247                         return;
1248
1249                 case XCLIB_XCOUT_SENTCONVSEL:
1250                         if (evt.type != SelectionNotify)
1251                                 return;
1252
1253                         if (target == m_utf8_string && evt.xselection.property == None) {
1254                                 *context= XCLIB_XCOUT_FALLBACK_UTF8;
1255                                 return;
1256                         }
1257                         else if (target == m_compound_text && evt.xselection.property == None) {
1258                                 *context= XCLIB_XCOUT_FALLBACK_COMP;
1259                                 return;
1260                         }
1261                         else if (target == m_text && evt.xselection.property == None) {
1262                                 *context= XCLIB_XCOUT_FALLBACK_TEXT;
1263                                 return;
1264                         }
1265
1266                         // find the size and format of the data in property
1267                         XGetWindowProperty(m_display, win, m_xclip_out, 0, 0, False,
1268                                 AnyPropertyType, &pty_type, &pty_format,
1269                                 &pty_items, &pty_size, &buffer);
1270                         XFree(buffer);
1271
1272                         if (pty_type == m_incr) {
1273                                 // start INCR mechanism by deleting property
1274                                 XDeleteProperty(m_display, win, m_xclip_out);
1275                                 XFlush(m_display);
1276                                 *context = XCLIB_XCOUT_INCR;
1277                                 return;
1278                         }
1279
1280                         // if it's not incr, and not format == 8, then there's
1281                         // nothing in the selection (that xclip understands, anyway)
1282
1283                         if (pty_format != 8) {
1284                                 *context = XCLIB_XCOUT_NONE;
1285                                 return;
1286                         }
1287
1288                         // not using INCR mechanism, just read the property
1289                         XGetWindowProperty(m_display, win, m_xclip_out, 0, (long) pty_size,
1290                                         False, AnyPropertyType, &pty_type,
1291                                         &pty_format, &pty_items, &pty_size, &buffer);
1292
1293                         // finished with property, delete it
1294                         XDeleteProperty(m_display, win, m_xclip_out);
1295
1296                         // copy the buffer to the pointer for returned data
1297                         ltxt = (unsigned char *) malloc(pty_items);
1298                         memcpy(ltxt, buffer, pty_items);
1299
1300                         // set the length of the returned data
1301                         *len = pty_items;
1302                         *txt = ltxt;
1303
1304                         // free the buffer
1305                         XFree(buffer);
1306
1307                         *context = XCLIB_XCOUT_NONE;
1308
1309                         // complete contents of selection fetched, return 1
1310                         return;
1311
1312                 case XCLIB_XCOUT_INCR:
1313                         // To use the INCR method, we basically delete the
1314                         // property with the selection in it, wait for an
1315                         // event indicating that the property has been created,
1316                         // then read it, delete it, etc.
1317
1318                         // make sure that the event is relevant
1319                         if (evt.type != PropertyNotify)
1320                                 return;
1321
1322                         // skip unless the property has a new value
1323                         if (evt.xproperty.state != PropertyNewValue)
1324                                 return;
1325
1326                         // check size and format of the property
1327                         XGetWindowProperty(m_display, win, m_xclip_out, 0, 0, False,
1328                                 AnyPropertyType, &pty_type, &pty_format,
1329                                 &pty_items, &pty_size, (unsigned char **) &buffer);
1330
1331                         if (pty_format != 8) {
1332                                 // property does not contain text, delete it
1333                                 // to tell the other X client that we have read 
1334                                 // it and to send the next property
1335                                 XFree(buffer);
1336                                 XDeleteProperty(m_display, win, m_xclip_out);
1337                                 return;
1338                         }
1339
1340                         if (pty_size == 0) {
1341                                 // no more data, exit from loop
1342                                 XFree(buffer);
1343                                 XDeleteProperty(m_display, win, m_xclip_out);
1344                                 *context = XCLIB_XCOUT_NONE;
1345
1346                                 // this means that an INCR transfer is now
1347                                 // complete, return 1
1348                                 return;
1349                         }
1350
1351                         XFree(buffer);
1352
1353                         // if we have come this far, the propery contains
1354                         // text, we know the size.
1355                         XGetWindowProperty(m_display, win, m_xclip_out, 0, (long) pty_size,
1356                                 False, AnyPropertyType, &pty_type, &pty_format,
1357                                 &pty_items, &pty_size, (unsigned char **) &buffer);
1358
1359                         // allocate memory to accommodate data in *txt
1360                         if (*len == 0) {
1361                                 *len = pty_items;
1362                                 ltxt = (unsigned char *) malloc(*len);
1363                         }
1364                         else {
1365                                 *len += pty_items;
1366                                 ltxt = (unsigned char *) realloc(ltxt, *len);
1367                         }
1368
1369                         // add data to ltxt
1370                         memcpy(&ltxt[*len - pty_items], buffer, pty_items);
1371
1372                         *txt = ltxt;
1373                         XFree(buffer);
1374
1375                         // delete property to get the next item
1376                         XDeleteProperty(m_display, win, m_xclip_out);
1377                         XFlush(m_display);
1378                         return;
1379         }
1380         return;
1381 }
1382
1383 GHOST_TUns8 *GHOST_SystemX11::getClipboard(bool selection) const
1384 {
1385         Atom sseln;
1386         Atom target= m_string;
1387         Window owner;
1388
1389         // from xclip.c doOut() v0.11
1390         unsigned char *sel_buf;
1391         unsigned long sel_len= 0;
1392         XEvent evt;
1393         unsigned int context= XCLIB_XCOUT_NONE;
1394
1395         if (selection == True)
1396                 sseln= m_primary;
1397         else
1398                 sseln= m_clipboard;
1399
1400         vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();
1401         vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
1402         GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
1403         Window win = window->getXWindow();
1404
1405         /* check if we are the owner. */
1406         owner= XGetSelectionOwner(m_display, sseln);
1407         if (owner == win) {
1408                 if (sseln == m_clipboard) {
1409                         sel_buf= (unsigned char *)malloc(strlen(txt_cut_buffer)+1);
1410                         strcpy((char *)sel_buf, txt_cut_buffer);
1411                         return((GHOST_TUns8*)sel_buf);
1412                 }
1413                 else {
1414                         sel_buf= (unsigned char *)malloc(strlen(txt_select_buffer)+1);
1415                         strcpy((char *)sel_buf, txt_select_buffer);
1416                         return((GHOST_TUns8*)sel_buf);
1417                 }
1418         }
1419         else if (owner == None)
1420                 return(NULL);
1421
1422         while (1) {
1423                 /* only get an event if xcout() is doing something */
1424                 if (context != XCLIB_XCOUT_NONE)
1425                         XNextEvent(m_display, &evt);
1426
1427                 /* fetch the selection, or part of it */
1428                 getClipboard_xcout(evt, sseln, target, &sel_buf, &sel_len, &context);
1429
1430                 /* fallback is needed. set XA_STRING to target and restart the loop. */
1431                 if (context == XCLIB_XCOUT_FALLBACK) {
1432                         context= XCLIB_XCOUT_NONE;
1433                         target= m_string;
1434                         continue;
1435                 }
1436                 else if (context == XCLIB_XCOUT_FALLBACK_UTF8) {
1437                         /* utf8 fail, move to compouned text. */
1438                         context= XCLIB_XCOUT_NONE;
1439                         target= m_compound_text;
1440                         continue;
1441                 }
1442                 else if (context == XCLIB_XCOUT_FALLBACK_COMP) {
1443                         /* compouned text faile, move to text. */
1444                         context= XCLIB_XCOUT_NONE;
1445                         target= m_text;
1446                         continue;
1447                 }
1448
1449                 /* only continue if xcout() is doing something */
1450                 if (context == XCLIB_XCOUT_NONE)
1451                         break;
1452         }
1453
1454         if (sel_len) {
1455                 /* only print the buffer out, and free it, if it's not
1456                  * empty
1457                  */
1458                 unsigned char *tmp_data = (unsigned char*) malloc(sel_len+1);
1459                 memcpy((char*)tmp_data, (char*)sel_buf, sel_len);
1460                 tmp_data[sel_len] = '\0';
1461                 
1462                 if (sseln == m_string)
1463                         XFree(sel_buf);
1464                 else
1465                         free(sel_buf);
1466                 
1467                 return (GHOST_TUns8*)tmp_data;
1468         }
1469         return(NULL);
1470 }
1471
1472 void GHOST_SystemX11::putClipboard(GHOST_TInt8 *buffer, bool selection) const
1473 {
1474         Window m_window, owner;
1475
1476         vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();      
1477         vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
1478         GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
1479         m_window = window->getXWindow();
1480
1481         if (buffer) {
1482                 if (selection == False) {
1483                         XSetSelectionOwner(m_display, m_clipboard, m_window, CurrentTime);
1484                         owner= XGetSelectionOwner(m_display, m_clipboard);
1485                         if (txt_cut_buffer)
1486                                 free((void*)txt_cut_buffer);
1487
1488                         txt_cut_buffer = (char*) malloc(strlen(buffer)+1);
1489                         strcpy(txt_cut_buffer, buffer);
1490                 } else {
1491                         XSetSelectionOwner(m_display, m_primary, m_window, CurrentTime);
1492                         owner= XGetSelectionOwner(m_display, m_primary);
1493                         if (txt_select_buffer)
1494                                 free((void*)txt_select_buffer);
1495
1496                         txt_select_buffer = (char*) malloc(strlen(buffer)+1);
1497                         strcpy(txt_select_buffer, buffer);
1498                 }
1499
1500                 if (owner != m_window)
1501                         fprintf(stderr, "failed to own primary\n");
1502         }
1503 }