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