Cocoa fix [#21866] : force mouse move event to be sent upon cursor position set request
[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 #ifdef HAVE_CONFIG_H
33 #include <config.h>
34 #endif
35
36 #include "GHOST_SystemX11.h"
37 #include "GHOST_WindowX11.h"
38 #include "GHOST_WindowManager.h"
39 #include "GHOST_TimerManager.h"
40 #include "GHOST_EventCursor.h"
41 #include "GHOST_EventKey.h"
42 #include "GHOST_EventButton.h"
43 #include "GHOST_EventWheel.h"
44 #include "GHOST_EventNDOF.h"
45 #include "GHOST_NDOFManager.h"
46 #include "GHOST_DisplayManagerX11.h"
47
48 #include "GHOST_Debug.h"
49
50 #include <X11/Xatom.h>
51 #include <X11/keysym.h>
52 #include <X11/XKBlib.h> /* allow detectable autorepeate */
53
54 #ifdef __sgi
55
56 #if defined(_SGI_EXTRA_PREDEFINES) && !defined(NO_FAST_ATOMS)
57 #include <X11/SGIFastAtom.h>
58 #else
59 #define XSGIFastInternAtom(dpy,string,fast_name,how) XInternAtom(dpy,string,how)
60 #endif
61
62 #endif
63
64 // For timing
65
66 #include <sys/time.h>
67 #include <unistd.h>
68
69 #include <iostream>
70 #include <vector>
71 #include <stdio.h> // for fprintf only
72 #include <cstdlib> // for exit
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, 2); /* 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
855         // Shift
856         if ((m_keyboard_vector[shift_l >> 3] >> (shift_l & 7)) & 1) {
857                 keys.set(GHOST_kModifierKeyLeftShift,true);
858         } else {
859                 keys.set(GHOST_kModifierKeyLeftShift,false);
860         }
861         if ((m_keyboard_vector[shift_r >> 3] >> (shift_r & 7)) & 1) {
862
863                 keys.set(GHOST_kModifierKeyRightShift,true);
864         } else {
865                 keys.set(GHOST_kModifierKeyRightShift,false);
866         }
867
868         // control (weep)
869         if ((m_keyboard_vector[control_l >> 3] >> (control_l & 7)) & 1) {
870                 keys.set(GHOST_kModifierKeyLeftControl,true);
871         } else {
872                 keys.set(GHOST_kModifierKeyLeftControl,false);
873         }
874         if ((m_keyboard_vector[control_r >> 3] >> (control_r & 7)) & 1) {
875                 keys.set(GHOST_kModifierKeyRightControl,true);
876         } else {
877                 keys.set(GHOST_kModifierKeyRightControl,false);
878         }
879
880         // Alt (yawn)
881         if ((m_keyboard_vector[alt_l >> 3] >> (alt_l & 7)) & 1) {
882                 keys.set(GHOST_kModifierKeyLeftAlt,true);
883         } else {
884                 keys.set(GHOST_kModifierKeyLeftAlt,false);
885         }       
886         if ((m_keyboard_vector[alt_r >> 3] >> (alt_r & 7)) & 1) {
887                 keys.set(GHOST_kModifierKeyRightAlt,true);
888         } else {
889                 keys.set(GHOST_kModifierKeyRightAlt,false);
890         }
891         return GHOST_kSuccess;
892 }
893
894         GHOST_TSuccess 
895 GHOST_SystemX11::
896 getButtons(
897         GHOST_Buttons& buttons
898 ) const {
899
900         Window root_return, child_return;
901         int rx,ry,wx,wy;
902         unsigned int mask_return;
903
904         if (XQueryPointer(
905                 m_display,
906                 RootWindow(m_display,DefaultScreen(m_display)),
907                 &root_return,
908                 &child_return,
909                 &rx,&ry,
910                 &wx,&wy,
911                 &mask_return
912         ) == False) {
913                 return GHOST_kFailure;
914         } else {
915
916                 if (mask_return & Button1Mask) {
917                         buttons.set(GHOST_kButtonMaskLeft,true);
918                 } else {
919                         buttons.set(GHOST_kButtonMaskLeft,false);
920                 }
921
922                 if (mask_return & Button2Mask) {
923                         buttons.set(GHOST_kButtonMaskMiddle,true);
924                 } else {
925                         buttons.set(GHOST_kButtonMaskMiddle,false);
926                 }
927
928                 if (mask_return & Button3Mask) {
929                         buttons.set(GHOST_kButtonMaskRight,true);
930                 } else {
931                         buttons.set(GHOST_kButtonMaskRight,false);
932                 }
933         }       
934
935         return GHOST_kSuccess;
936 }
937
938
939         GHOST_TSuccess 
940 GHOST_SystemX11::
941 getCursorPosition(
942         GHOST_TInt32& x,
943         GHOST_TInt32& y
944 ) const {
945
946         Window root_return, child_return;
947         int rx,ry,wx,wy;
948         unsigned int mask_return;
949
950         if (XQueryPointer(
951                 m_display,
952                 RootWindow(m_display,DefaultScreen(m_display)),
953                 &root_return,
954                 &child_return,
955                 &rx,&ry,
956                 &wx,&wy,
957                 &mask_return
958         ) == False) {
959                 return GHOST_kFailure;
960         } else {
961                 x = rx;
962                 y = ry;
963         }       
964         return GHOST_kSuccess;
965 }
966
967
968         GHOST_TSuccess 
969 GHOST_SystemX11::
970 setCursorPosition(
971         GHOST_TInt32 x,
972         GHOST_TInt32 y
973 ) {
974
975         // This is a brute force move in screen coordinates
976         // XWarpPointer does relative moves so first determine the
977         // current pointer position.
978
979         int cx,cy;
980         if (getCursorPosition(cx,cy) == GHOST_kFailure) {
981                 return GHOST_kFailure;
982         }
983
984         int relx = x-cx;
985         int rely = y-cy;
986
987         XWarpPointer(m_display,None,None,0,0,0,0,relx,rely);
988         XSync(m_display, 0); /* Sync to process all requests */
989         
990         return GHOST_kSuccess;
991 }
992
993
994         void
995 GHOST_SystemX11::
996 addDirtyWindow(
997         GHOST_WindowX11 * bad_wind
998 ){
999
1000         GHOST_ASSERT((bad_wind != NULL), "addDirtyWindow() NULL ptr trapped (window)");
1001         
1002         m_dirty_windows.push_back(bad_wind);
1003 }
1004
1005
1006         bool
1007 GHOST_SystemX11::
1008 generateWindowExposeEvents(
1009 ){
1010
1011         vector<GHOST_WindowX11 *>::iterator w_start = m_dirty_windows.begin();
1012         vector<GHOST_WindowX11 *>::const_iterator w_end = m_dirty_windows.end();
1013         bool anyProcessed = false;
1014         
1015         for (;w_start != w_end; ++w_start) {
1016                 GHOST_Event * g_event = new 
1017                         GHOST_Event(
1018                                 getMilliSeconds(),
1019                                 GHOST_kEventWindowUpdate,
1020                                 *w_start
1021                         );                      
1022
1023                 (*w_start)->validate(); 
1024                 
1025                 if (g_event) {
1026                         pushEvent(g_event);
1027                         anyProcessed = true;
1028                 }
1029         }
1030
1031         m_dirty_windows.clear();
1032         return anyProcessed;
1033 }
1034
1035 #define GXMAP(k,x,y) case x: k = y; break; 
1036
1037         GHOST_TKey
1038 GHOST_SystemX11::
1039 convertXKey(
1040         KeySym key
1041 ){
1042         GHOST_TKey type;
1043
1044         if ((key >= XK_A) && (key <= XK_Z)) {
1045                 type = GHOST_TKey( key - XK_A + int(GHOST_kKeyA));
1046         } else if ((key >= XK_a) && (key <= XK_z)) {
1047                 type = GHOST_TKey(key - XK_a + int(GHOST_kKeyA));
1048         } else if ((key >= XK_0) && (key <= XK_9)) {
1049                 type = GHOST_TKey(key - XK_0 + int(GHOST_kKey0));
1050         } else if ((key >= XK_F1) && (key <= XK_F24)) {
1051                 type = GHOST_TKey(key - XK_F1 + int(GHOST_kKeyF1));
1052 #if defined(__sun) || defined(__sun__) 
1053                 /* This is a bit of a hack, but it looks like sun
1054                    Used F11 and friends for its special keys Stop,again etc..
1055                    So this little patch enables F11 and F12 to work as expected
1056                    following link has documentation on it: 
1057                    http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4734408
1058                    also from /usr/include/X11/Sunkeysym.h 
1059 #define SunXK_F36               0x1005FF10      // Labeled F11
1060 #define SunXK_F37               0x1005FF11      // Labeled F12 
1061
1062                                 mein@cs.umn.edu
1063                  */
1064                 
1065         } else if (key == 268828432) {
1066                 type = GHOST_kKeyF11;
1067         } else if (key == 268828433) {
1068                 type = GHOST_kKeyF12;
1069 #endif
1070         } else {
1071                 switch(key) {
1072                         GXMAP(type,XK_BackSpace,        GHOST_kKeyBackSpace);
1073                         GXMAP(type,XK_Tab,              GHOST_kKeyTab);
1074                         GXMAP(type,XK_Return,           GHOST_kKeyEnter);
1075                         GXMAP(type,XK_Escape,           GHOST_kKeyEsc);
1076                         GXMAP(type,XK_space,            GHOST_kKeySpace);
1077                         
1078                         GXMAP(type,XK_Linefeed,         GHOST_kKeyLinefeed);
1079                         GXMAP(type,XK_semicolon,        GHOST_kKeySemicolon);
1080                         GXMAP(type,XK_period,           GHOST_kKeyPeriod);
1081                         GXMAP(type,XK_comma,            GHOST_kKeyComma);
1082                         GXMAP(type,XK_quoteright,       GHOST_kKeyQuote);
1083                         GXMAP(type,XK_quoteleft,        GHOST_kKeyAccentGrave);
1084                         GXMAP(type,XK_minus,            GHOST_kKeyMinus);
1085                         GXMAP(type,XK_slash,            GHOST_kKeySlash);
1086                         GXMAP(type,XK_backslash,        GHOST_kKeyBackslash);
1087                         GXMAP(type,XK_equal,            GHOST_kKeyEqual);
1088                         GXMAP(type,XK_bracketleft,      GHOST_kKeyLeftBracket);
1089                         GXMAP(type,XK_bracketright,     GHOST_kKeyRightBracket);
1090                         GXMAP(type,XK_Pause,            GHOST_kKeyPause);
1091                         
1092                         GXMAP(type,XK_Shift_L,          GHOST_kKeyLeftShift);
1093                         GXMAP(type,XK_Shift_R,          GHOST_kKeyRightShift);
1094                         GXMAP(type,XK_Control_L,        GHOST_kKeyLeftControl);
1095                         GXMAP(type,XK_Control_R,        GHOST_kKeyRightControl);
1096                         GXMAP(type,XK_Alt_L,            GHOST_kKeyLeftAlt);
1097                         GXMAP(type,XK_Alt_R,            GHOST_kKeyRightAlt);
1098
1099                         GXMAP(type,XK_Insert,           GHOST_kKeyInsert);
1100                         GXMAP(type,XK_Delete,           GHOST_kKeyDelete);
1101                         GXMAP(type,XK_Home,                     GHOST_kKeyHome);
1102                         GXMAP(type,XK_End,                      GHOST_kKeyEnd);
1103                         GXMAP(type,XK_Page_Up,          GHOST_kKeyUpPage);
1104                         GXMAP(type,XK_Page_Down,        GHOST_kKeyDownPage);
1105
1106                         GXMAP(type,XK_Left,                     GHOST_kKeyLeftArrow);
1107                         GXMAP(type,XK_Right,            GHOST_kKeyRightArrow);
1108                         GXMAP(type,XK_Up,                       GHOST_kKeyUpArrow);
1109                         GXMAP(type,XK_Down,                     GHOST_kKeyDownArrow);
1110
1111                         GXMAP(type,XK_Caps_Lock,        GHOST_kKeyCapsLock);
1112                         GXMAP(type,XK_Scroll_Lock,      GHOST_kKeyScrollLock);
1113                         GXMAP(type,XK_Num_Lock,         GHOST_kKeyNumLock);
1114                         
1115                                 /* keypad events */
1116                                 
1117                         GXMAP(type,XK_KP_0,                     GHOST_kKeyNumpad0);
1118                         GXMAP(type,XK_KP_1,                     GHOST_kKeyNumpad1);
1119                         GXMAP(type,XK_KP_2,                     GHOST_kKeyNumpad2);
1120                         GXMAP(type,XK_KP_3,                     GHOST_kKeyNumpad3);
1121                         GXMAP(type,XK_KP_4,                     GHOST_kKeyNumpad4);
1122                         GXMAP(type,XK_KP_5,                     GHOST_kKeyNumpad5);
1123                         GXMAP(type,XK_KP_6,                     GHOST_kKeyNumpad6);
1124                         GXMAP(type,XK_KP_7,                     GHOST_kKeyNumpad7);
1125                         GXMAP(type,XK_KP_8,                     GHOST_kKeyNumpad8);
1126                         GXMAP(type,XK_KP_9,                     GHOST_kKeyNumpad9);
1127                         GXMAP(type,XK_KP_Decimal,       GHOST_kKeyNumpadPeriod);
1128
1129                         GXMAP(type,XK_KP_Insert,        GHOST_kKeyNumpad0);
1130                         GXMAP(type,XK_KP_End,           GHOST_kKeyNumpad1);
1131                         GXMAP(type,XK_KP_Down,          GHOST_kKeyNumpad2);
1132                         GXMAP(type,XK_KP_Page_Down,     GHOST_kKeyNumpad3);
1133                         GXMAP(type,XK_KP_Left,          GHOST_kKeyNumpad4);
1134                         GXMAP(type,XK_KP_Begin,         GHOST_kKeyNumpad5);
1135                         GXMAP(type,XK_KP_Right,         GHOST_kKeyNumpad6);
1136                         GXMAP(type,XK_KP_Home,          GHOST_kKeyNumpad7);
1137                         GXMAP(type,XK_KP_Up,            GHOST_kKeyNumpad8);
1138                         GXMAP(type,XK_KP_Page_Up,       GHOST_kKeyNumpad9);
1139                         GXMAP(type,XK_KP_Delete,        GHOST_kKeyNumpadPeriod);
1140
1141                         GXMAP(type,XK_KP_Enter,         GHOST_kKeyNumpadEnter);
1142                         GXMAP(type,XK_KP_Add,           GHOST_kKeyNumpadPlus);
1143                         GXMAP(type,XK_KP_Subtract,      GHOST_kKeyNumpadMinus);
1144                         GXMAP(type,XK_KP_Multiply,      GHOST_kKeyNumpadAsterisk);
1145                         GXMAP(type,XK_KP_Divide,        GHOST_kKeyNumpadSlash);
1146
1147                                 /* some extra sun cruft (NICE KEYBOARD!) */
1148 #ifdef __sun__
1149                         GXMAP(type,0xffde,                      GHOST_kKeyNumpad1);
1150                         GXMAP(type,0xffe0,                      GHOST_kKeyNumpad3);
1151                         GXMAP(type,0xffdc,                      GHOST_kKeyNumpad5);
1152                         GXMAP(type,0xffd8,                      GHOST_kKeyNumpad7);
1153                         GXMAP(type,0xffda,                      GHOST_kKeyNumpad9);
1154
1155                         GXMAP(type,0xffd6,                      GHOST_kKeyNumpadSlash);
1156                         GXMAP(type,0xffd7,                      GHOST_kKeyNumpadAsterisk);
1157 #endif
1158
1159                         default :
1160                                 type = GHOST_kKeyUnknown;
1161                                 break;
1162                 }
1163         }
1164
1165         return type;
1166 }
1167
1168 #undef GXMAP
1169
1170 /* from xclip.c xcout() v0.11 */
1171
1172 #define XCLIB_XCOUT_NONE                0 /* no context */
1173 #define XCLIB_XCOUT_SENTCONVSEL         1 /* sent a request */
1174 #define XCLIB_XCOUT_INCR                2 /* in an incr loop */
1175 #define XCLIB_XCOUT_FALLBACK            3 /* STRING failed, need fallback to UTF8 */
1176 #define XCLIB_XCOUT_FALLBACK_UTF8       4 /* UTF8 failed, move to compouned */
1177 #define XCLIB_XCOUT_FALLBACK_COMP       5 /* compouned failed, move to text. */
1178 #define XCLIB_XCOUT_FALLBACK_TEXT       6
1179
1180 // Retrieves the contents of a selections.
1181 void GHOST_SystemX11::getClipboard_xcout(XEvent evt,
1182         Atom sel, Atom target, unsigned char **txt,
1183         unsigned long *len, unsigned int *context) const
1184 {
1185         Atom pty_type;
1186         int pty_format;
1187         unsigned char *buffer;
1188         unsigned long pty_size, pty_items;
1189         unsigned char *ltxt= *txt;
1190
1191         vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();
1192         vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
1193         GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
1194         Window win = window->getXWindow();
1195
1196         switch (*context) {
1197                 // There is no context, do an XConvertSelection()
1198                 case XCLIB_XCOUT_NONE:
1199                         // Initialise return length to 0
1200                         if (*len > 0) {
1201                                 free(*txt);
1202                                 *len = 0;
1203                         }
1204
1205                         // Send a selection request
1206                         XConvertSelection(m_display, sel, target, m_xclip_out, win, CurrentTime);
1207                         *context = XCLIB_XCOUT_SENTCONVSEL;
1208                         return;
1209
1210                 case XCLIB_XCOUT_SENTCONVSEL:
1211                         if (evt.type != SelectionNotify)
1212                                 return;
1213
1214                         if (target == m_utf8_string && evt.xselection.property == None) {
1215                                 *context= XCLIB_XCOUT_FALLBACK_UTF8;
1216                                 return;
1217                         }
1218                         else if (target == m_compound_text && evt.xselection.property == None) {
1219                                 *context= XCLIB_XCOUT_FALLBACK_COMP;
1220                                 return;
1221                         }
1222                         else if (target == m_text && evt.xselection.property == None) {
1223                                 *context= XCLIB_XCOUT_FALLBACK_TEXT;
1224                                 return;
1225                         }
1226
1227                         // find the size and format of the data in property
1228                         XGetWindowProperty(m_display, win, m_xclip_out, 0, 0, False,
1229                                 AnyPropertyType, &pty_type, &pty_format,
1230                                 &pty_items, &pty_size, &buffer);
1231                         XFree(buffer);
1232
1233                         if (pty_type == m_incr) {
1234                                 // start INCR mechanism by deleting property
1235                                 XDeleteProperty(m_display, win, m_xclip_out);
1236                                 XFlush(m_display);
1237                                 *context = XCLIB_XCOUT_INCR;
1238                                 return;
1239                         }
1240
1241                         // if it's not incr, and not format == 8, then there's
1242                         // nothing in the selection (that xclip understands, anyway)
1243
1244                         if (pty_format != 8) {
1245                                 *context = XCLIB_XCOUT_NONE;
1246                                 return;
1247                         }
1248
1249                         // not using INCR mechanism, just read the property
1250                         XGetWindowProperty(m_display, win, m_xclip_out, 0, (long) pty_size,
1251                                         False, AnyPropertyType, &pty_type,
1252                                         &pty_format, &pty_items, &pty_size, &buffer);
1253
1254                         // finished with property, delete it
1255                         XDeleteProperty(m_display, win, m_xclip_out);
1256
1257                         // copy the buffer to the pointer for returned data
1258                         ltxt = (unsigned char *) malloc(pty_items);
1259                         memcpy(ltxt, buffer, pty_items);
1260
1261                         // set the length of the returned data
1262                         *len = pty_items;
1263                         *txt = ltxt;
1264
1265                         // free the buffer
1266                         XFree(buffer);
1267
1268                         *context = XCLIB_XCOUT_NONE;
1269
1270                         // complete contents of selection fetched, return 1
1271                         return;
1272
1273                 case XCLIB_XCOUT_INCR:
1274                         // To use the INCR method, we basically delete the
1275                         // property with the selection in it, wait for an
1276                         // event indicating that the property has been created,
1277                         // then read it, delete it, etc.
1278
1279                         // make sure that the event is relevant
1280                         if (evt.type != PropertyNotify)
1281                                 return;
1282
1283                         // skip unless the property has a new value
1284                         if (evt.xproperty.state != PropertyNewValue)
1285                                 return;
1286
1287                         // check size and format of the property
1288                         XGetWindowProperty(m_display, win, m_xclip_out, 0, 0, False,
1289                                 AnyPropertyType, &pty_type, &pty_format,
1290                                 &pty_items, &pty_size, (unsigned char **) &buffer);
1291
1292                         if (pty_format != 8) {
1293                                 // property does not contain text, delete it
1294                                 // to tell the other X client that we have read 
1295                                 // it and to send the next property
1296                                 XFree(buffer);
1297                                 XDeleteProperty(m_display, win, m_xclip_out);
1298                                 return;
1299                         }
1300
1301                         if (pty_size == 0) {
1302                                 // no more data, exit from loop
1303                                 XFree(buffer);
1304                                 XDeleteProperty(m_display, win, m_xclip_out);
1305                                 *context = XCLIB_XCOUT_NONE;
1306
1307                                 // this means that an INCR transfer is now
1308                                 // complete, return 1
1309                                 return;
1310                         }
1311
1312                         XFree(buffer);
1313
1314                         // if we have come this far, the propery contains
1315                         // text, we know the size.
1316                         XGetWindowProperty(m_display, win, m_xclip_out, 0, (long) pty_size,
1317                                 False, AnyPropertyType, &pty_type, &pty_format,
1318                                 &pty_items, &pty_size, (unsigned char **) &buffer);
1319
1320                         // allocate memory to accommodate data in *txt
1321                         if (*len == 0) {
1322                                 *len = pty_items;
1323                                 ltxt = (unsigned char *) malloc(*len);
1324                         }
1325                         else {
1326                                 *len += pty_items;
1327                                 ltxt = (unsigned char *) realloc(ltxt, *len);
1328                         }
1329
1330                         // add data to ltxt
1331                         memcpy(&ltxt[*len - pty_items], buffer, pty_items);
1332
1333                         *txt = ltxt;
1334                         XFree(buffer);
1335
1336                         // delete property to get the next item
1337                         XDeleteProperty(m_display, win, m_xclip_out);
1338                         XFlush(m_display);
1339                         return;
1340         }
1341         return;
1342 }
1343
1344 GHOST_TUns8 *GHOST_SystemX11::getClipboard(bool selection) const
1345 {
1346         Atom sseln;
1347         Atom target= m_string;
1348         Window owner;
1349
1350         // from xclip.c doOut() v0.11
1351         unsigned char *sel_buf;
1352         unsigned long sel_len= 0;
1353         XEvent evt;
1354         unsigned int context= XCLIB_XCOUT_NONE;
1355
1356         if (selection == True)
1357                 sseln= m_primary;
1358         else
1359                 sseln= m_clipboard;
1360
1361         vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();
1362         vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
1363         GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
1364         Window win = window->getXWindow();
1365
1366         /* check if we are the owner. */
1367         owner= XGetSelectionOwner(m_display, sseln);
1368         if (owner == win) {
1369                 if (sseln == m_clipboard) {
1370                         sel_buf= (unsigned char *)malloc(strlen(txt_cut_buffer)+1);
1371                         strcpy((char *)sel_buf, txt_cut_buffer);
1372                         return((GHOST_TUns8*)sel_buf);
1373                 }
1374                 else {
1375                         sel_buf= (unsigned char *)malloc(strlen(txt_select_buffer)+1);
1376                         strcpy((char *)sel_buf, txt_select_buffer);
1377                         return((GHOST_TUns8*)sel_buf);
1378                 }
1379         }
1380         else if (owner == None)
1381                 return(NULL);
1382
1383         while (1) {
1384                 /* only get an event if xcout() is doing something */
1385                 if (context != XCLIB_XCOUT_NONE)
1386                         XNextEvent(m_display, &evt);
1387
1388                 /* fetch the selection, or part of it */
1389                 getClipboard_xcout(evt, sseln, target, &sel_buf, &sel_len, &context);
1390
1391                 /* fallback is needed. set XA_STRING to target and restart the loop. */
1392                 if (context == XCLIB_XCOUT_FALLBACK) {
1393                         context= XCLIB_XCOUT_NONE;
1394                         target= m_string;
1395                         continue;
1396                 }
1397                 else if (context == XCLIB_XCOUT_FALLBACK_UTF8) {
1398                         /* utf8 fail, move to compouned text. */
1399                         context= XCLIB_XCOUT_NONE;
1400                         target= m_compound_text;
1401                         continue;
1402                 }
1403                 else if (context == XCLIB_XCOUT_FALLBACK_COMP) {
1404                         /* compouned text faile, move to text. */
1405                         context= XCLIB_XCOUT_NONE;
1406                         target= m_text;
1407                         continue;
1408                 }
1409
1410                 /* only continue if xcout() is doing something */
1411                 if (context == XCLIB_XCOUT_NONE)
1412                         break;
1413         }
1414
1415         if (sel_len) {
1416                 /* only print the buffer out, and free it, if it's not
1417                  * empty
1418                  */
1419                 unsigned char *tmp_data = (unsigned char*) malloc(sel_len+1);
1420                 memcpy((char*)tmp_data, (char*)sel_buf, sel_len);
1421                 tmp_data[sel_len] = '\0';
1422                 
1423                 if (sseln == m_string)
1424                         XFree(sel_buf);
1425                 else
1426                         free(sel_buf);
1427                 
1428                 return (GHOST_TUns8*)tmp_data;
1429         }
1430         return(NULL);
1431 }
1432
1433 void GHOST_SystemX11::putClipboard(GHOST_TInt8 *buffer, bool selection) const
1434 {
1435         Window m_window, owner;
1436
1437         vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();      
1438         vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
1439         GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
1440         m_window = window->getXWindow();
1441
1442         if (buffer) {
1443                 if (selection == False) {
1444                         XSetSelectionOwner(m_display, m_clipboard, m_window, CurrentTime);
1445                         owner= XGetSelectionOwner(m_display, m_clipboard);
1446                         if (txt_cut_buffer)
1447                                 free((void*)txt_cut_buffer);
1448
1449                         txt_cut_buffer = (char*) malloc(strlen(buffer)+1);
1450                         strcpy(txt_cut_buffer, buffer);
1451                 } else {
1452                         XSetSelectionOwner(m_display, m_primary, m_window, CurrentTime);
1453                         owner= XGetSelectionOwner(m_display, m_primary);
1454                         if (txt_select_buffer)
1455                                 free((void*)txt_select_buffer);
1456
1457                         txt_select_buffer = (char*) malloc(strlen(buffer)+1);
1458                         strcpy(txt_select_buffer, buffer);
1459                 }
1460         
1461                 if (owner != m_window)
1462                         fprintf(stderr, "failed to own primary\n");
1463         }
1464 }
1465
1466 const GHOST_TUns8* GHOST_SystemX11::getSystemDir() const
1467 {
1468         return (GHOST_TUns8*)"/usr/share/blender";
1469 }
1470
1471 const GHOST_TUns8* GHOST_SystemX11::getUserDir() const
1472 {
1473         static char path[256];
1474         char* env = getenv("HOME");
1475         if(env) {
1476                 strncpy(path, env, 245);
1477                 path[245]=0;
1478                 strcat(path, "/.blender/");
1479                 return (GHOST_TUns8*) path;
1480         } else {
1481                 return NULL;
1482         }
1483 }