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