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