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