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