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