Merge with 2.5 -r 21788:22040.
[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                                 XWindowAttributes attr;
538                                 Window fwin;
539                                 int revert_to;
540
541                                 /* as ICCCM say, we need reply this event
542                                  * with a SetInputFocus, the data[1] have
543                                  * the valid timestamp (send by the wm).
544                                  *
545                                  * Some WM send this event before the
546                                  * window is really mapped (for example
547                                  * change from virtual desktop), so we need
548                                  * to be sure that our windows is mapped
549                                  * or this call fail and close blender.
550                                  */
551                                 if (XGetWindowAttributes(m_display, xcme.window, &attr) == True) {
552                                         if (XGetInputFocus(m_display, &fwin, &revert_to) == True) {
553                                                 if (attr.map_state == IsViewable) {
554                                                         if (fwin != xcme.window)
555                                                                 XSetInputFocus(m_display, xcme.window, RevertToParent, xcme.data.l[1]);
556                                                 }
557                                         }
558                                 }
559                         } else {
560                                 /* Unknown client message, ignore */
561                         }
562                         break;
563                 }
564                 
565                 case DestroyNotify:
566                         ::exit(-1);     
567                 // We're not interested in the following things.(yet...)
568                 case NoExpose : 
569                 case GraphicsExpose :
570                         break;
571                 
572                 case EnterNotify:
573                 case LeaveNotify:
574                 {
575                         // XCrossingEvents pointer leave enter window.
576                         // also do cursor move here, MotionNotify only
577                         // happens when motion starts & ends inside window
578                         XCrossingEvent &xce = xe->xcrossing;
579                         
580                         g_event = new 
581                         GHOST_EventCursor(
582                                 getMilliSeconds(),
583                                 GHOST_kEventCursorMove,
584                                 window,
585                                 xce.x_root,
586                                 xce.y_root
587                         );
588                         break;
589                 }
590                 case MapNotify:
591                         /*
592                          * From ICCCM:
593                          * [ Clients can select for StructureNotify on their
594                          *   top-level windows to track transition between
595                          *   Normal and Iconic states. Receipt of a MapNotify
596                          *   event will indicate a transition to the Normal
597                          *   state, and receipt of an UnmapNotify event will
598                          *   indicate a transition to the Iconic state. ]
599                          */
600                         if (window->m_post_init == True) {
601                                 /*
602                                  * Now we are sure that the window is
603                                  * mapped, so only need change the state.
604                                  */
605                                 window->setState (window->m_post_state);
606                                 window->m_post_init = False;
607                         }
608                         break;
609                 case UnmapNotify:
610                         break;
611                 case MappingNotify:
612                 case ReparentNotify:
613                         break;
614                 case SelectionRequest:
615                 {
616                         XEvent nxe;
617                         Atom target, string, compound_text, c_string;
618                         XSelectionRequestEvent *xse = &xe->xselectionrequest;
619                         
620                         target = XInternAtom(m_display, "TARGETS", False);
621                         string = XInternAtom(m_display, "STRING", False);
622                         compound_text = XInternAtom(m_display, "COMPOUND_TEXT", False);
623                         c_string = XInternAtom(m_display, "C_STRING", False);
624                         
625                         /* support obsolete clients */
626                         if (xse->property == None) {
627                                 xse->property = xse->target;
628                         }
629                         
630                         nxe.xselection.type = SelectionNotify;
631                         nxe.xselection.requestor = xse->requestor;
632                         nxe.xselection.property = xse->property;
633                         nxe.xselection.display = xse->display;
634                         nxe.xselection.selection = xse->selection;
635                         nxe.xselection.target = xse->target;
636                         nxe.xselection.time = xse->time;
637                         
638                         /*Check to see if the requestor is asking for String*/
639                         if(xse->target == string || xse->target == compound_text || xse->target == c_string) {
640                                 if (xse->selection == XInternAtom(m_display, "PRIMARY", False)) {
641                                         XChangeProperty(m_display, xse->requestor, xse->property, xse->target, 8, PropModeReplace, (unsigned char*)txt_select_buffer, strlen(txt_select_buffer));
642                                 } else if (xse->selection == XInternAtom(m_display, "CLIPBOARD", False)) {
643                                         XChangeProperty(m_display, xse->requestor, xse->property, xse->target, 8, PropModeReplace, (unsigned char*)txt_cut_buffer, strlen(txt_cut_buffer));
644                                 }
645                         } else if (xse->target == target) {
646                                 Atom alist[4];
647                                 alist[0] = target;
648                                 alist[1] = string;
649                                 alist[2] = compound_text;
650                                 alist[3] = c_string;
651                                 XChangeProperty(m_display, xse->requestor, xse->property, xse->target, 32, PropModeReplace, (unsigned char*)alist, 4);
652                                 XFlush(m_display);
653                         } else  {
654                                 //Change property to None because we do not support anything but STRING
655                                 nxe.xselection.property = None;
656                         }
657                         
658                         //Send the event to the client 0 0 == False, SelectionNotify
659                         XSendEvent(m_display, xse->requestor, 0, 0, &nxe);
660                         XFlush(m_display);
661                         break;
662                 }
663                 
664                 default: {
665                         if(xe->type == window->GetXTablet().MotionEvent) 
666                         {
667                                 XDeviceMotionEvent* data = (XDeviceMotionEvent*)xe;
668                                 window->GetXTablet().CommonData.Pressure= 
669                                         data->axis_data[2]/((float)window->GetXTablet().PressureLevels);
670                         
671                         /* the (short) cast and the &0xffff is bizarre and unexplained anywhere,
672                          * but I got garbage data without it. Found it in the xidump.c source --matt */
673                                 window->GetXTablet().CommonData.Xtilt= 
674                                         (short)(data->axis_data[3]&0xffff)/((float)window->GetXTablet().XtiltLevels);
675                                 window->GetXTablet().CommonData.Ytilt= 
676                                         (short)(data->axis_data[4]&0xffff)/((float)window->GetXTablet().YtiltLevels);
677                         }
678                         else if(xe->type == window->GetXTablet().ProxInEvent) 
679                         {
680                                 XProximityNotifyEvent* data = (XProximityNotifyEvent*)xe;
681                                 if(data->deviceid == window->GetXTablet().StylusID)
682                                         window->GetXTablet().CommonData.Active= 1;
683                                 else if(data->deviceid == window->GetXTablet().EraserID)
684                                         window->GetXTablet().CommonData.Active= 2;
685                         }
686                         else if(xe->type == window->GetXTablet().ProxOutEvent)
687                                 window->GetXTablet().CommonData.Active= 0;
688
689                         break;
690                 }
691         }
692
693         if (g_event) {
694                 pushEvent(g_event);
695         }
696 }
697
698         void *
699 GHOST_SystemX11::
700 prepareNdofInfo(volatile GHOST_TEventNDOFData *currentNdofValues)
701 {
702         const vector<GHOST_IWindow*>& v(m_windowManager->getWindows());
703         if (v.size() > 0)
704                 sNdofInfo.window = static_cast<GHOST_WindowX11*>(v[0])->getXWindow();
705         sNdofInfo.display = m_display;
706         sNdofInfo.currValues = currentNdofValues;
707         return (void*)&sNdofInfo;
708 }
709
710         GHOST_TSuccess 
711 GHOST_SystemX11::
712 getModifierKeys(
713         GHOST_ModifierKeys& keys
714 ) const {
715
716         // analyse the masks retuned from XQueryPointer.
717
718         memset(m_keyboard_vector,0,sizeof(m_keyboard_vector));
719
720         XQueryKeymap(m_display,m_keyboard_vector);
721
722         // now translate key symobols into keycodes and
723         // test with vector.
724
725         const KeyCode shift_l = XKeysymToKeycode(m_display,XK_Shift_L);
726         const KeyCode shift_r = XKeysymToKeycode(m_display,XK_Shift_R);
727         const KeyCode control_l = XKeysymToKeycode(m_display,XK_Control_L);
728         const KeyCode control_r = XKeysymToKeycode(m_display,XK_Control_R);
729         const KeyCode alt_l = XKeysymToKeycode(m_display,XK_Alt_L);
730         const KeyCode alt_r = XKeysymToKeycode(m_display,XK_Alt_R);
731
732         // Shift
733         if ((m_keyboard_vector[shift_l >> 3] >> (shift_l & 7)) & 1) {
734                 keys.set(GHOST_kModifierKeyLeftShift,true);
735         } else {
736                 keys.set(GHOST_kModifierKeyLeftShift,false);
737         }
738         if ((m_keyboard_vector[shift_r >> 3] >> (shift_r & 7)) & 1) {
739
740                 keys.set(GHOST_kModifierKeyRightShift,true);
741         } else {
742                 keys.set(GHOST_kModifierKeyRightShift,false);
743         }
744
745         // control (weep)
746         if ((m_keyboard_vector[control_l >> 3] >> (control_l & 7)) & 1) {
747                 keys.set(GHOST_kModifierKeyLeftControl,true);
748         } else {
749                 keys.set(GHOST_kModifierKeyLeftControl,false);
750         }
751         if ((m_keyboard_vector[control_r >> 3] >> (control_r & 7)) & 1) {
752                 keys.set(GHOST_kModifierKeyRightControl,true);
753         } else {
754                 keys.set(GHOST_kModifierKeyRightControl,false);
755         }
756
757         // Alt (yawn)
758         if ((m_keyboard_vector[alt_l >> 3] >> (alt_l & 7)) & 1) {
759                 keys.set(GHOST_kModifierKeyLeftAlt,true);
760         } else {
761                 keys.set(GHOST_kModifierKeyLeftAlt,false);
762         }       
763         if ((m_keyboard_vector[alt_r >> 3] >> (alt_r & 7)) & 1) {
764                 keys.set(GHOST_kModifierKeyRightAlt,true);
765         } else {
766                 keys.set(GHOST_kModifierKeyRightAlt,false);
767         }
768         return GHOST_kSuccess;
769 }
770
771         GHOST_TSuccess 
772 GHOST_SystemX11::
773 getButtons(
774         GHOST_Buttons& buttons
775 ) const {
776
777         Window root_return, child_return;
778         int rx,ry,wx,wy;
779         unsigned int mask_return;
780
781         if (XQueryPointer(
782                 m_display,
783                 RootWindow(m_display,DefaultScreen(m_display)),
784                 &root_return,
785                 &child_return,
786                 &rx,&ry,
787                 &wx,&wy,
788                 &mask_return
789         ) == False) {
790                 return GHOST_kFailure;
791         } else {
792
793                 if (mask_return & Button1Mask) {
794                         buttons.set(GHOST_kButtonMaskLeft,true);
795                 } else {
796                         buttons.set(GHOST_kButtonMaskLeft,false);
797                 }
798
799                 if (mask_return & Button2Mask) {
800                         buttons.set(GHOST_kButtonMaskMiddle,true);
801                 } else {
802                         buttons.set(GHOST_kButtonMaskMiddle,false);
803                 }
804
805                 if (mask_return & Button3Mask) {
806                         buttons.set(GHOST_kButtonMaskRight,true);
807                 } else {
808                         buttons.set(GHOST_kButtonMaskRight,false);
809                 }
810         }       
811
812         return GHOST_kSuccess;
813 }
814
815
816         GHOST_TSuccess 
817 GHOST_SystemX11::
818 getCursorPosition(
819         GHOST_TInt32& x,
820         GHOST_TInt32& y
821 ) const {
822
823         Window root_return, child_return;
824         int rx,ry,wx,wy;
825         unsigned int mask_return;
826
827         if (XQueryPointer(
828                 m_display,
829                 RootWindow(m_display,DefaultScreen(m_display)),
830                 &root_return,
831                 &child_return,
832                 &rx,&ry,
833                 &wx,&wy,
834                 &mask_return
835         ) == False) {
836                 return GHOST_kFailure;
837         } else {
838                 x = rx;
839                 y = ry;
840         }       
841         return GHOST_kSuccess;
842 }
843
844
845         GHOST_TSuccess 
846 GHOST_SystemX11::
847 setCursorPosition(
848         GHOST_TInt32 x,
849         GHOST_TInt32 y
850 ) const {
851
852         // This is a brute force move in screen coordinates
853         // XWarpPointer does relative moves so first determine the
854         // current pointer position.
855
856         int cx,cy;
857         if (getCursorPosition(cx,cy) == GHOST_kFailure) {
858                 return GHOST_kFailure;
859         }
860
861         int relx = x-cx;
862         int rely = y-cy;
863
864         XWarpPointer(m_display,None,None,0,0,0,0,relx,rely);
865         XFlush(m_display);
866         
867         return GHOST_kSuccess;
868 }
869
870
871         void
872 GHOST_SystemX11::
873 addDirtyWindow(
874         GHOST_WindowX11 * bad_wind
875 ){
876
877         GHOST_ASSERT((bad_wind != NULL), "addDirtyWindow() NULL ptr trapped (window)");
878         
879         m_dirty_windows.push_back(bad_wind);
880 }
881
882
883         bool
884 GHOST_SystemX11::
885 generateWindowExposeEvents(
886 ){
887
888         vector<GHOST_WindowX11 *>::iterator w_start = m_dirty_windows.begin();
889         vector<GHOST_WindowX11 *>::const_iterator w_end = m_dirty_windows.end();
890         bool anyProcessed = false;
891         
892         for (;w_start != w_end; ++w_start) {
893                 GHOST_Event * g_event = new 
894                         GHOST_Event(
895                                 getMilliSeconds(),
896                                 GHOST_kEventWindowUpdate,
897                                 *w_start
898                         );                      
899
900                 (*w_start)->validate(); 
901                 
902                 if (g_event) {
903                         pushEvent(g_event);
904                         anyProcessed = true;
905                 }
906         }
907
908         m_dirty_windows.clear();
909         return anyProcessed;
910 }
911
912 #define GXMAP(k,x,y) case x: k = y; break; 
913
914         GHOST_TKey
915 GHOST_SystemX11::
916 convertXKey(
917         KeySym key
918 ){
919         GHOST_TKey type;
920
921         if ((key >= XK_A) && (key <= XK_Z)) {
922                 type = GHOST_TKey( key - XK_A + int(GHOST_kKeyA));
923         } else if ((key >= XK_a) && (key <= XK_z)) {
924                 type = GHOST_TKey(key - XK_a + int(GHOST_kKeyA));
925         } else if ((key >= XK_0) && (key <= XK_9)) {
926                 type = GHOST_TKey(key - XK_0 + int(GHOST_kKey0));
927         } else if ((key >= XK_F1) && (key <= XK_F24)) {
928                 type = GHOST_TKey(key - XK_F1 + int(GHOST_kKeyF1));
929 #if defined(__sun) || defined(__sun__) 
930                 /* This is a bit of a hack, but it looks like sun
931                    Used F11 and friends for its special keys Stop,again etc..
932                    So this little patch enables F11 and F12 to work as expected
933                    following link has documentation on it: 
934                    http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4734408
935                    also from /usr/include/X11/Sunkeysym.h 
936 #define SunXK_F36               0x1005FF10      // Labeled F11
937 #define SunXK_F37               0x1005FF11      // Labeled F12 
938
939                                 mein@cs.umn.edu
940                  */
941                 
942         } else if (key == 268828432) {
943                 type = GHOST_kKeyF11;
944         } else if (key == 268828433) {
945                 type = GHOST_kKeyF12;
946 #endif
947         } else {
948                 switch(key) {
949                         GXMAP(type,XK_BackSpace,        GHOST_kKeyBackSpace);
950                         GXMAP(type,XK_Tab,              GHOST_kKeyTab);
951                         GXMAP(type,XK_Return,           GHOST_kKeyEnter);
952                         GXMAP(type,XK_Escape,           GHOST_kKeyEsc);
953                         GXMAP(type,XK_space,            GHOST_kKeySpace);
954                         
955                         GXMAP(type,XK_Linefeed,         GHOST_kKeyLinefeed);
956                         GXMAP(type,XK_semicolon,        GHOST_kKeySemicolon);
957                         GXMAP(type,XK_period,           GHOST_kKeyPeriod);
958                         GXMAP(type,XK_comma,            GHOST_kKeyComma);
959                         GXMAP(type,XK_quoteright,       GHOST_kKeyQuote);
960                         GXMAP(type,XK_quoteleft,        GHOST_kKeyAccentGrave);
961                         GXMAP(type,XK_minus,            GHOST_kKeyMinus);
962                         GXMAP(type,XK_slash,            GHOST_kKeySlash);
963                         GXMAP(type,XK_backslash,        GHOST_kKeyBackslash);
964                         GXMAP(type,XK_equal,            GHOST_kKeyEqual);
965                         GXMAP(type,XK_bracketleft,      GHOST_kKeyLeftBracket);
966                         GXMAP(type,XK_bracketright,     GHOST_kKeyRightBracket);
967                         GXMAP(type,XK_Pause,            GHOST_kKeyPause);
968                         
969                         GXMAP(type,XK_Shift_L,          GHOST_kKeyLeftShift);
970                         GXMAP(type,XK_Shift_R,          GHOST_kKeyRightShift);
971                         GXMAP(type,XK_Control_L,        GHOST_kKeyLeftControl);
972                         GXMAP(type,XK_Control_R,        GHOST_kKeyRightControl);
973                         GXMAP(type,XK_Alt_L,            GHOST_kKeyLeftAlt);
974                         GXMAP(type,XK_Alt_R,            GHOST_kKeyRightAlt);
975
976                         GXMAP(type,XK_Insert,           GHOST_kKeyInsert);
977                         GXMAP(type,XK_Delete,           GHOST_kKeyDelete);
978                         GXMAP(type,XK_Home,                     GHOST_kKeyHome);
979                         GXMAP(type,XK_End,                      GHOST_kKeyEnd);
980                         GXMAP(type,XK_Page_Up,          GHOST_kKeyUpPage);
981                         GXMAP(type,XK_Page_Down,        GHOST_kKeyDownPage);
982
983                         GXMAP(type,XK_Left,                     GHOST_kKeyLeftArrow);
984                         GXMAP(type,XK_Right,            GHOST_kKeyRightArrow);
985                         GXMAP(type,XK_Up,                       GHOST_kKeyUpArrow);
986                         GXMAP(type,XK_Down,                     GHOST_kKeyDownArrow);
987
988                         GXMAP(type,XK_Caps_Lock,        GHOST_kKeyCapsLock);
989                         GXMAP(type,XK_Scroll_Lock,      GHOST_kKeyScrollLock);
990                         GXMAP(type,XK_Num_Lock,         GHOST_kKeyNumLock);
991                         
992                                 /* keypad events */
993                                 
994                         GXMAP(type,XK_KP_0,                     GHOST_kKeyNumpad0);
995                         GXMAP(type,XK_KP_1,                     GHOST_kKeyNumpad1);
996                         GXMAP(type,XK_KP_2,                     GHOST_kKeyNumpad2);
997                         GXMAP(type,XK_KP_3,                     GHOST_kKeyNumpad3);
998                         GXMAP(type,XK_KP_4,                     GHOST_kKeyNumpad4);
999                         GXMAP(type,XK_KP_5,                     GHOST_kKeyNumpad5);
1000                         GXMAP(type,XK_KP_6,                     GHOST_kKeyNumpad6);
1001                         GXMAP(type,XK_KP_7,                     GHOST_kKeyNumpad7);
1002                         GXMAP(type,XK_KP_8,                     GHOST_kKeyNumpad8);
1003                         GXMAP(type,XK_KP_9,                     GHOST_kKeyNumpad9);
1004                         GXMAP(type,XK_KP_Decimal,       GHOST_kKeyNumpadPeriod);
1005
1006                         GXMAP(type,XK_KP_Insert,        GHOST_kKeyNumpad0);
1007                         GXMAP(type,XK_KP_End,           GHOST_kKeyNumpad1);
1008                         GXMAP(type,XK_KP_Down,          GHOST_kKeyNumpad2);
1009                         GXMAP(type,XK_KP_Page_Down,     GHOST_kKeyNumpad3);
1010                         GXMAP(type,XK_KP_Left,          GHOST_kKeyNumpad4);
1011                         GXMAP(type,XK_KP_Begin,         GHOST_kKeyNumpad5);
1012                         GXMAP(type,XK_KP_Right,         GHOST_kKeyNumpad6);
1013                         GXMAP(type,XK_KP_Home,          GHOST_kKeyNumpad7);
1014                         GXMAP(type,XK_KP_Up,            GHOST_kKeyNumpad8);
1015                         GXMAP(type,XK_KP_Page_Up,       GHOST_kKeyNumpad9);
1016                         GXMAP(type,XK_KP_Delete,        GHOST_kKeyNumpadPeriod);
1017
1018                         GXMAP(type,XK_KP_Enter,         GHOST_kKeyNumpadEnter);
1019                         GXMAP(type,XK_KP_Add,           GHOST_kKeyNumpadPlus);
1020                         GXMAP(type,XK_KP_Subtract,      GHOST_kKeyNumpadMinus);
1021                         GXMAP(type,XK_KP_Multiply,      GHOST_kKeyNumpadAsterisk);
1022                         GXMAP(type,XK_KP_Divide,        GHOST_kKeyNumpadSlash);
1023
1024                                 /* some extra sun cruft (NICE KEYBOARD!) */
1025 #ifdef __sun__
1026                         GXMAP(type,0xffde,                      GHOST_kKeyNumpad1);
1027                         GXMAP(type,0xffe0,                      GHOST_kKeyNumpad3);
1028                         GXMAP(type,0xffdc,                      GHOST_kKeyNumpad5);
1029                         GXMAP(type,0xffd8,                      GHOST_kKeyNumpad7);
1030                         GXMAP(type,0xffda,                      GHOST_kKeyNumpad9);
1031
1032                         GXMAP(type,0xffd6,                      GHOST_kKeyNumpadSlash);
1033                         GXMAP(type,0xffd7,                      GHOST_kKeyNumpadAsterisk);
1034 #endif
1035
1036                         default :
1037                                 type = GHOST_kKeyUnknown;
1038                                 break;
1039                 }
1040         }
1041
1042         return type;
1043 }
1044
1045 #undef GXMAP
1046
1047 /* from xclip.c xcout() v0.11 */
1048
1049 #define XCLIB_XCOUT_NONE                0 /* no context */
1050 #define XCLIB_XCOUT_SENTCONVSEL         1 /* sent a request */
1051 #define XCLIB_XCOUT_INCR                2 /* in an incr loop */
1052 #define XCLIB_XCOUT_FALLBACK            3 /* STRING failed, need fallback to UTF8 */
1053 #define XCLIB_XCOUT_FALLBACK_UTF8       4 /* UTF8 failed, move to compouned */
1054 #define XCLIB_XCOUT_FALLBACK_COMP       5 /* compouned failed, move to text. */
1055 #define XCLIB_XCOUT_FALLBACK_TEXT       6
1056
1057 // Retrieves the contents of a selections.
1058 void GHOST_SystemX11::getClipboard_xcout(XEvent evt,
1059         Atom sel, Atom target, unsigned char **txt,
1060         unsigned long *len, unsigned int *context) const
1061 {
1062         Atom pty_type;
1063         int pty_format;
1064         unsigned char *buffer;
1065         unsigned long pty_size, pty_items;
1066         unsigned char *ltxt= *txt;
1067
1068         vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();
1069         vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
1070         GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
1071         Window win = window->getXWindow();
1072
1073         switch (*context) {
1074                 // There is no context, do an XConvertSelection()
1075                 case XCLIB_XCOUT_NONE:
1076                         // Initialise return length to 0
1077                         if (*len > 0) {
1078                                 free(*txt);
1079                                 *len = 0;
1080                         }
1081
1082                         // Send a selection request
1083                         XConvertSelection(m_display, sel, target, m_xclip_out, win, CurrentTime);
1084                         *context = XCLIB_XCOUT_SENTCONVSEL;
1085                         return;
1086
1087                 case XCLIB_XCOUT_SENTCONVSEL:
1088                         if (evt.type != SelectionNotify)
1089                                 return;
1090
1091                         if (target == m_utf8_string && evt.xselection.property == None) {
1092                                 *context= XCLIB_XCOUT_FALLBACK_UTF8;
1093                                 return;
1094                         }
1095                         else if (target == m_compound_text && evt.xselection.property == None) {
1096                                 *context= XCLIB_XCOUT_FALLBACK_COMP;
1097                                 return;
1098                         }
1099                         else if (target == m_text && evt.xselection.property == None) {
1100                                 *context= XCLIB_XCOUT_FALLBACK_TEXT;
1101                                 return;
1102                         }
1103
1104                         // find the size and format of the data in property
1105                         XGetWindowProperty(m_display, win, m_xclip_out, 0, 0, False,
1106                                 AnyPropertyType, &pty_type, &pty_format,
1107                                 &pty_items, &pty_size, &buffer);
1108                         XFree(buffer);
1109
1110                         if (pty_type == m_incr) {
1111                                 // start INCR mechanism by deleting property
1112                                 XDeleteProperty(m_display, win, m_xclip_out);
1113                                 XFlush(m_display);
1114                                 *context = XCLIB_XCOUT_INCR;
1115                                 return;
1116                         }
1117
1118                         // if it's not incr, and not format == 8, then there's
1119                         // nothing in the selection (that xclip understands, anyway)
1120
1121                         if (pty_format != 8) {
1122                                 *context = XCLIB_XCOUT_NONE;
1123                                 return;
1124                         }
1125
1126                         // not using INCR mechanism, just read the property
1127                         XGetWindowProperty(m_display, win, m_xclip_out, 0, (long) pty_size,
1128                                         False, AnyPropertyType, &pty_type,
1129                                         &pty_format, &pty_items, &pty_size, &buffer);
1130
1131                         // finished with property, delete it
1132                         XDeleteProperty(m_display, win, m_xclip_out);
1133
1134                         // copy the buffer to the pointer for returned data
1135                         ltxt = (unsigned char *) malloc(pty_items);
1136                         memcpy(ltxt, buffer, pty_items);
1137
1138                         // set the length of the returned data
1139                         *len = pty_items;
1140                         *txt = ltxt;
1141
1142                         // free the buffer
1143                         XFree(buffer);
1144
1145                         *context = XCLIB_XCOUT_NONE;
1146
1147                         // complete contents of selection fetched, return 1
1148                         return;
1149
1150                 case XCLIB_XCOUT_INCR:
1151                         // To use the INCR method, we basically delete the
1152                         // property with the selection in it, wait for an
1153                         // event indicating that the property has been created,
1154                         // then read it, delete it, etc.
1155
1156                         // make sure that the event is relevant
1157                         if (evt.type != PropertyNotify)
1158                                 return;
1159
1160                         // skip unless the property has a new value
1161                         if (evt.xproperty.state != PropertyNewValue)
1162                                 return;
1163
1164                         // check size and format of the property
1165                         XGetWindowProperty(m_display, win, m_xclip_out, 0, 0, False,
1166                                 AnyPropertyType, &pty_type, &pty_format,
1167                                 &pty_items, &pty_size, (unsigned char **) &buffer);
1168
1169                         if (pty_format != 8) {
1170                                 // property does not contain text, delete it
1171                                 // to tell the other X client that we have read 
1172                                 // it and to send the next property
1173                                 XFree(buffer);
1174                                 XDeleteProperty(m_display, win, m_xclip_out);
1175                                 return;
1176                         }
1177
1178                         if (pty_size == 0) {
1179                                 // no more data, exit from loop
1180                                 XFree(buffer);
1181                                 XDeleteProperty(m_display, win, m_xclip_out);
1182                                 *context = XCLIB_XCOUT_NONE;
1183
1184                                 // this means that an INCR transfer is now
1185                                 // complete, return 1
1186                                 return;
1187                         }
1188
1189                         XFree(buffer);
1190
1191                         // if we have come this far, the propery contains
1192                         // text, we know the size.
1193                         XGetWindowProperty(m_display, win, m_xclip_out, 0, (long) pty_size,
1194                                 False, AnyPropertyType, &pty_type, &pty_format,
1195                                 &pty_items, &pty_size, (unsigned char **) &buffer);
1196
1197                         // allocate memory to accommodate data in *txt
1198                         if (*len == 0) {
1199                                 *len = pty_items;
1200                                 ltxt = (unsigned char *) malloc(*len);
1201                         }
1202                         else {
1203                                 *len += pty_items;
1204                                 ltxt = (unsigned char *) realloc(ltxt, *len);
1205                         }
1206
1207                         // add data to ltxt
1208                         memcpy(&ltxt[*len - pty_items], buffer, pty_items);
1209
1210                         *txt = ltxt;
1211                         XFree(buffer);
1212
1213                         // delete property to get the next item
1214                         XDeleteProperty(m_display, win, m_xclip_out);
1215                         XFlush(m_display);
1216                         return;
1217         }
1218         return;
1219 }
1220
1221 GHOST_TUns8 *GHOST_SystemX11::getClipboard(bool selection) const
1222 {
1223         Atom sseln;
1224         Atom target= m_string;
1225         Window owner;
1226
1227         // from xclip.c doOut() v0.11
1228         unsigned char *sel_buf;
1229         unsigned long sel_len= 0;
1230         XEvent evt;
1231         unsigned int context= XCLIB_XCOUT_NONE;
1232
1233         if (selection == True)
1234                 sseln= m_primary;
1235         else
1236                 sseln= m_clipboard;
1237
1238         vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();
1239         vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
1240         GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
1241         Window win = window->getXWindow();
1242
1243         /* check if we are the owner. */
1244         owner= XGetSelectionOwner(m_display, sseln);
1245         if (owner == win) {
1246                 if (sseln == m_clipboard) {
1247                         sel_buf= (unsigned char *)malloc(strlen(txt_cut_buffer)+1);
1248                         strcpy((char *)sel_buf, txt_cut_buffer);
1249                         return((GHOST_TUns8*)sel_buf);
1250                 }
1251                 else {
1252                         sel_buf= (unsigned char *)malloc(strlen(txt_select_buffer)+1);
1253                         strcpy((char *)sel_buf, txt_select_buffer);
1254                         return((GHOST_TUns8*)sel_buf);
1255                 }
1256         }
1257         else if (owner == None)
1258                 return(NULL);
1259
1260         while (1) {
1261                 /* only get an event if xcout() is doing something */
1262                 if (context != XCLIB_XCOUT_NONE)
1263                         XNextEvent(m_display, &evt);
1264
1265                 /* fetch the selection, or part of it */
1266                 getClipboard_xcout(evt, sseln, target, &sel_buf, &sel_len, &context);
1267
1268                 /* fallback is needed. set XA_STRING to target and restart the loop. */
1269                 if (context == XCLIB_XCOUT_FALLBACK) {
1270                         context= XCLIB_XCOUT_NONE;
1271                         target= m_string;
1272                         continue;
1273                 }
1274                 else if (context == XCLIB_XCOUT_FALLBACK_UTF8) {
1275                         /* utf8 fail, move to compouned text. */
1276                         context= XCLIB_XCOUT_NONE;
1277                         target= m_compound_text;
1278                         continue;
1279                 }
1280                 else if (context == XCLIB_XCOUT_FALLBACK_COMP) {
1281                         /* compouned text faile, move to text. */
1282                         context= XCLIB_XCOUT_NONE;
1283                         target= m_text;
1284                         continue;
1285                 }
1286
1287                 /* only continue if xcout() is doing something */
1288                 if (context == XCLIB_XCOUT_NONE)
1289                         break;
1290         }
1291
1292         if (sel_len) {
1293                 /* only print the buffer out, and free it, if it's not
1294                  * empty
1295                  */
1296                 unsigned char *tmp_data = (unsigned char*) malloc(sel_len+1);
1297                 memcpy((char*)tmp_data, (char*)sel_buf, sel_len);
1298                 tmp_data[sel_len] = '\0';
1299                 
1300                 if (sseln == m_string)
1301                         XFree(sel_buf);
1302                 else
1303                         free(sel_buf);
1304                 
1305                 return (GHOST_TUns8*)tmp_data;
1306         }
1307         return(NULL);
1308 }
1309
1310 void GHOST_SystemX11::putClipboard(GHOST_TInt8 *buffer, bool selection) const
1311 {
1312         Window m_window, owner;
1313
1314         vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();      
1315         vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
1316         GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
1317         m_window = window->getXWindow();
1318
1319         if (buffer) {
1320                 if (selection == False) {
1321                         XSetSelectionOwner(m_display, m_clipboard, m_window, CurrentTime);
1322                         owner= XGetSelectionOwner(m_display, m_clipboard);
1323                         if (txt_cut_buffer)
1324                                 free((void*)txt_cut_buffer);
1325
1326                         txt_cut_buffer = (char*) malloc(strlen(buffer)+1);
1327                         strcpy(txt_cut_buffer, buffer);
1328                 } else {
1329                         XSetSelectionOwner(m_display, m_primary, m_window, CurrentTime);
1330                         owner= XGetSelectionOwner(m_display, m_primary);
1331                         if (txt_select_buffer)
1332                                 free((void*)txt_select_buffer);
1333
1334                         txt_select_buffer = (char*) malloc(strlen(buffer)+1);
1335                         strcpy(txt_select_buffer, buffer);
1336                 }
1337         
1338                 if (owner != m_window)
1339                         fprintf(stderr, "failed to own primary\n");
1340         }
1341 }