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