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